Skip to content

Commit b11386f

Browse files
committed
Make it possible to redirect not only errs() but also outs()
This change is for those who use lld as a library. Context: https://reviews.llvm.org/D70287 This patch adds a new parmeter to lld::*::link() so that we can pass an raw_ostream object representing stdout. Previously, lld::*::link() took only an stderr object. Justification for making stdoutOS and stderrOS mandatory: I wanted to make link() functions to take stdout and stderr in that order. However, if we change the function signature from bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stderrOS = llvm::errs()); to bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS = llvm::outs(), raw_ostream &stderrOS = llvm::errs()); , then the meaning of existing code that passes stderrOS silently changes (stderrOS would be interpreted as stdoutOS). So, I chose to make existing code not to compile, so that developers can fix their code. Differential Revision: https://reviews.llvm.org/D70292
1 parent 5d67d81 commit b11386f

21 files changed

+121
-101
lines changed

lld/COFF/Driver.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,17 @@ static Timer inputFileTimer("Input File Reading", Timer::root());
6262
Configuration *config;
6363
LinkerDriver *driver;
6464

65-
bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &diag) {
65+
bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
66+
raw_ostream &stderrOS) {
6667
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
67-
errorHandler().errorOS = &diag;
6868
errorHandler().errorLimitExceededMsg =
6969
"too many errors emitted, stopping now"
7070
" (use /errorlimit:0 to see all errors)";
7171
errorHandler().exitEarly = canExitEarly;
72-
enableColors(diag.has_colors());
72+
enableColors(stderrOS.has_colors());
73+
74+
lld::stdoutOS = &stdoutOS;
75+
lld::stderrOS = &stderrOS;
7376

7477
config = make<Configuration>();
7578
symtab = make<SymbolTable>();
@@ -1150,7 +1153,7 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
11501153
// because it doesn't start with "/", but we deliberately chose "--" to
11511154
// avoid conflict with /version and for compatibility with clang-cl.
11521155
if (args.hasArg(OPT_dash_dash_version)) {
1153-
outs() << getLLDVersion() << "\n";
1156+
lld::outs() << getLLDVersion() << "\n";
11541157
return;
11551158
}
11561159

lld/COFF/DriverUtils.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -907,7 +907,7 @@ std::vector<const char *> ArgParser::tokenize(StringRef s) {
907907
}
908908

909909
void printHelp(const char *argv0) {
910-
COFFOptTable().PrintHelp(outs(),
910+
COFFOptTable().PrintHelp(lld::outs(),
911911
(std::string(argv0) + " [options] file...").c_str(),
912912
"LLVM Linker", false);
913913
}

lld/COFF/Writer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1844,7 +1844,7 @@ void Writer::sortExceptionTable() {
18441844
[](const Entry &a, const Entry &b) { return a.begin < b.begin; });
18451845
return;
18461846
}
1847-
errs() << "warning: don't know how to handle .pdata.\n";
1847+
lld::errs() << "warning: don't know how to handle .pdata.\n";
18481848
}
18491849

18501850
// The CRT section contains, among other things, the array of function

lld/Common/ErrorHandler.cpp

+20-15
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ using namespace llvm;
2626
using namespace lld;
2727

2828
// The functions defined in this file can be called from multiple threads,
29-
// but outs() or errs() are not thread-safe. We protect them using a mutex.
29+
// but lld::outs() or lld::errs() are not thread-safe. We protect them using a
30+
// mutex.
3031
static std::mutex mu;
3132

3233
// We want to separate multi-line messages with a newline. `sep` is "\n"
@@ -39,14 +40,18 @@ static StringRef getSeparator(const Twine &msg) {
3940
return "";
4041
}
4142

43+
raw_ostream *lld::stdoutOS;
44+
raw_ostream *lld::stderrOS;
45+
46+
raw_ostream &lld::outs() { return stdoutOS ? *stdoutOS : llvm::outs(); }
47+
raw_ostream &lld::errs() { return stderrOS ? *stderrOS : llvm::errs(); }
48+
4249
ErrorHandler &lld::errorHandler() {
4350
static ErrorHandler handler;
4451
return handler;
4552
}
4653

47-
void lld::enableColors(bool enable) {
48-
errorHandler().errorOS->enable_colors(enable);
49-
}
54+
void lld::enableColors(bool enable) { lld::errs().enable_colors(enable); }
5055

5156
void lld::exitLld(int val) {
5257
// Delete any temporary file, while keeping the memory mapping open.
@@ -58,8 +63,8 @@ void lld::exitLld(int val) {
5863
// build allows us to get the output of -time-passes.
5964
llvm_shutdown();
6065

61-
outs().flush();
62-
errs().flush();
66+
lld::outs().flush();
67+
lld::errs().flush();
6368
_exit(val);
6469
}
6570

@@ -149,13 +154,13 @@ void ErrorHandler::log(const Twine &msg) {
149154
if (!verbose)
150155
return;
151156
std::lock_guard<std::mutex> lock(mu);
152-
*errorOS << logName << ": " << msg << "\n";
157+
lld::errs() << logName << ": " << msg << "\n";
153158
}
154159

155160
void ErrorHandler::message(const Twine &msg) {
156161
std::lock_guard<std::mutex> lock(mu);
157-
outs() << msg << "\n";
158-
outs().flush();
162+
lld::outs() << msg << "\n";
163+
lld::outs().flush();
159164
}
160165

161166
void ErrorHandler::warn(const Twine &msg) {
@@ -165,8 +170,8 @@ void ErrorHandler::warn(const Twine &msg) {
165170
}
166171

167172
std::lock_guard<std::mutex> lock(mu);
168-
*errorOS << sep << getLocation(msg) << ": " << Colors::MAGENTA
169-
<< "warning: " << Colors::RESET << msg << "\n";
173+
lld::errs() << sep << getLocation(msg) << ": " << Colors::MAGENTA
174+
<< "warning: " << Colors::RESET << msg << "\n";
170175
sep = getSeparator(msg);
171176
}
172177

@@ -190,11 +195,11 @@ void ErrorHandler::error(const Twine &msg) {
190195
std::lock_guard<std::mutex> lock(mu);
191196

192197
if (errorLimit == 0 || errorCount < errorLimit) {
193-
*errorOS << sep << getLocation(msg) << ": " << Colors::RED
194-
<< "error: " << Colors::RESET << msg << "\n";
198+
lld::errs() << sep << getLocation(msg) << ": " << Colors::RED
199+
<< "error: " << Colors::RESET << msg << "\n";
195200
} else if (errorCount == errorLimit) {
196-
*errorOS << sep << getLocation(msg) << ": " << Colors::RED
197-
<< "error: " << Colors::RESET << errorLimitExceededMsg << "\n";
201+
lld::errs() << sep << getLocation(msg) << ": " << Colors::RED
202+
<< "error: " << Colors::RESET << errorLimitExceededMsg << "\n";
198203
if (exitEarly)
199204
exitLld(1);
200205
}

lld/ELF/Driver.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,17 @@ LinkerDriver *driver;
7575
static void setConfigs(opt::InputArgList &args);
7676
static void readConfigs(opt::InputArgList &args);
7777

78-
bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &error) {
78+
bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
79+
raw_ostream &stderrOS) {
7980
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
8081
errorHandler().errorLimitExceededMsg =
8182
"too many errors emitted, stopping now (use "
8283
"-error-limit=0 to see all errors)";
83-
errorHandler().errorOS = &error;
8484
errorHandler().exitEarly = canExitEarly;
85-
enableColors(error.has_colors());
85+
enableColors(stderrOS.has_colors());
86+
87+
lld::stdoutOS = &stdoutOS;
88+
lld::stderrOS = &stderrOS;
8689

8790
inputSections.clear();
8891
outputSections.clear();

lld/ELF/DriverUtils.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,16 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) {
145145

146146
void printHelp() {
147147
ELFOptTable().PrintHelp(
148-
outs(), (config->progName + " [options] file...").str().c_str(), "lld",
149-
false /*ShowHidden*/, true /*ShowAllAliases*/);
150-
outs() << "\n";
148+
lld::outs(), (config->progName + " [options] file...").str().c_str(),
149+
"lld", false /*ShowHidden*/, true /*ShowAllAliases*/);
150+
lld::outs() << "\n";
151151

152152
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
153153
// recent version as of March 2017) expect /: supported targets:.* elf/
154154
// in a message for the -help option. If it doesn't match, the scripts
155155
// assume that the linker doesn't support very basic features such as
156156
// shared libraries. Therefore, we need to print out at least "elf".
157-
outs() << config->progName << ": supported targets: elf\n";
157+
lld::outs() << config->progName << ": supported targets: elf\n";
158158
}
159159

160160
static std::string rewritePath(StringRef s) {

lld/ELF/MapFile.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ void writeMapFile() {
213213
}
214214

215215
static void print(StringRef a, StringRef b) {
216-
outs() << left_justify(a, 49) << " " << b << "\n";
216+
lld::outs() << left_justify(a, 49) << " " << b << "\n";
217217
}
218218

219219
// Output a cross reference table to stdout. This is for --cref.
@@ -244,7 +244,7 @@ void writeCrossReferenceTable() {
244244
}
245245

246246
// Print out a header.
247-
outs() << "Cross Reference Table\n\n";
247+
lld::outs() << "Cross Reference Table\n\n";
248248
print("Symbol", "File");
249249

250250
// Print out a table.

lld/MinGW/Driver.cpp

+9-6
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ class MinGWOptTable : public opt::OptTable {
8383

8484
static void printHelp(const char *argv0) {
8585
MinGWOptTable().PrintHelp(
86-
outs(), (std::string(argv0) + " [options] file...").c_str(), "lld",
86+
lld::outs(), (std::string(argv0) + " [options] file...").c_str(), "lld",
8787
false /*ShowHidden*/, true /*ShowAllAliases*/);
88-
outs() << "\n";
88+
lld::outs() << "\n";
8989
}
9090

9191
static cl::TokenizerCallback getQuotingStyle() {
@@ -159,8 +159,11 @@ searchLibrary(StringRef name, ArrayRef<StringRef> searchPaths, bool bStatic) {
159159

160160
// Convert Unix-ish command line arguments to Windows-ish ones and
161161
// then call coff::link.
162-
bool mingw::link(ArrayRef<const char *> argsArr, raw_ostream &diag) {
163-
enableColors(diag.has_colors());
162+
bool mingw::link(ArrayRef<const char *> argsArr, bool canExitEarly,
163+
raw_ostream &stdoutOS, raw_ostream &stderrOS) {
164+
enableColors(stderrOS.has_colors());
165+
lld::stdoutOS = &stdoutOS;
166+
lld::stderrOS = &stderrOS;
164167

165168
MinGWOptTable parser;
166169
opt::InputArgList args = parser.parse(argsArr.slice(1));
@@ -372,7 +375,7 @@ bool mingw::link(ArrayRef<const char *> argsArr, raw_ostream &diag) {
372375
return false;
373376

374377
if (args.hasArg(OPT_verbose) || args.hasArg(OPT__HASH_HASH_HASH))
375-
outs() << llvm::join(linkArgs, " ") << "\n";
378+
lld::outs() << llvm::join(linkArgs, " ") << "\n";
376379

377380
if (args.hasArg(OPT__HASH_HASH_HASH))
378381
return true;
@@ -381,5 +384,5 @@ bool mingw::link(ArrayRef<const char *> argsArr, raw_ostream &diag) {
381384
std::vector<const char *> vec;
382385
for (const std::string &s : linkArgs)
383386
vec.push_back(s.c_str());
384-
return coff::link(vec, true);
387+
return coff::link(vec, true, stdoutOS, stderrOS);
385388
}

lld/include/lld/Common/Driver.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,27 @@
1515
namespace lld {
1616
namespace coff {
1717
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
18-
llvm::raw_ostream &diag = llvm::errs());
18+
llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
1919
}
2020

2121
namespace mingw {
22-
bool link(llvm::ArrayRef<const char *> args,
23-
llvm::raw_ostream &diag = llvm::errs());
22+
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
23+
llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
2424
}
2525

2626
namespace elf {
2727
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
28-
llvm::raw_ostream &diag = llvm::errs());
28+
llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
2929
}
3030

3131
namespace mach_o {
3232
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
33-
llvm::raw_ostream &diag = llvm::errs());
33+
llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
3434
}
3535

3636
namespace wasm {
3737
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
38-
llvm::raw_ostream &diag = llvm::errs());
38+
llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
3939
}
4040
}
4141

lld/include/lld/Common/ErrorHandler.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
//
6060
// warn() doesn't do anything but printing out a given message.
6161
//
62-
// It is not recommended to use llvm::outs() or llvm::errs() directly in lld
62+
// It is not recommended to use llvm::outs() or lld::errs() directly in lld
6363
// because they are not thread-safe. The functions declared in this file are
6464
// thread-safe.
6565
//
@@ -76,17 +76,25 @@
7676

7777
namespace llvm {
7878
class DiagnosticInfo;
79+
class raw_ostream;
7980
}
8081

8182
namespace lld {
8283

84+
// We wrap stdout and stderr so that you can pass alternative stdout/stderr as
85+
// arguments to lld::*::link() functions.
86+
extern llvm::raw_ostream *stdoutOS;
87+
extern llvm::raw_ostream *stderrOS;
88+
89+
llvm::raw_ostream &outs();
90+
llvm::raw_ostream &errs();
91+
8392
class ErrorHandler {
8493
public:
8594
uint64_t errorCount = 0;
8695
uint64_t errorLimit = 20;
8796
StringRef errorLimitExceededMsg = "too many errors emitted, stopping now";
8897
StringRef logName = "lld";
89-
llvm::raw_ostream *errorOS = &llvm::errs();
9098
bool exitEarly = true;
9199
bool fatalWarnings = false;
92100
bool verbose = false;

lld/include/lld/Common/LLVM.h

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ struct WasmSignature;
5555
} // namespace llvm
5656

5757
namespace lld {
58+
llvm::raw_ostream &outs();
59+
llvm::raw_ostream &errs();
60+
5861
// Casting operators.
5962
using llvm::cast;
6063
using llvm::cast_or_null;

lld/lib/Core/Resolver.cpp

+11-12
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ bool Resolver::resolveUndefines() {
223223
if (!file)
224224
return true;
225225
if (std::error_code ec = file->parse()) {
226-
llvm::errs() << "Cannot open " + file->path()
227-
<< ": " << ec.message() << "\n";
226+
lld::errs() << "Cannot open " + file->path() << ": " << ec.message()
227+
<< "\n";
228228
return false;
229229
}
230230
DEBUG_WITH_TYPE("resolver",
@@ -252,8 +252,8 @@ bool Resolver::resolveUndefines() {
252252
if (auto EC = undefAddedOrError.takeError()) {
253253
// FIXME: This should be passed to logAllUnhandledErrors but it needs
254254
// to be passed a Twine instead of a string.
255-
llvm::errs() << "Error in " + file->path() << ": ";
256-
logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
255+
lld::errs() << "Error in " + file->path() << ": ";
256+
logAllUnhandledErrors(std::move(EC), lld::errs(), std::string());
257257
return false;
258258
}
259259
undefAdded = undefAddedOrError.get();
@@ -266,8 +266,8 @@ bool Resolver::resolveUndefines() {
266266
if (auto EC = undefAddedOrError.takeError()) {
267267
// FIXME: This should be passed to logAllUnhandledErrors but it needs
268268
// to be passed a Twine instead of a string.
269-
llvm::errs() << "Error in " + file->path() << ": ";
270-
logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
269+
lld::errs() << "Error in " + file->path() << ": ";
270+
logAllUnhandledErrors(std::move(EC), lld::errs(), std::string());
271271
return false;
272272
}
273273
undefAdded = undefAddedOrError.get();
@@ -279,8 +279,8 @@ bool Resolver::resolveUndefines() {
279279
if (auto EC = handleSharedLibrary(*file)) {
280280
// FIXME: This should be passed to logAllUnhandledErrors but it needs
281281
// to be passed a Twine instead of a string.
282-
llvm::errs() << "Error in " + file->path() << ": ";
283-
logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
282+
lld::errs() << "Error in " + file->path() << ": ";
283+
logAllUnhandledErrors(std::move(EC), lld::errs(), std::string());
284284
return false;
285285
}
286286
break;
@@ -424,15 +424,14 @@ bool Resolver::checkUndefines() {
424424
// Seems like this symbol is undefined. Warn that.
425425
foundUndefines = true;
426426
if (_ctx.printRemainingUndefines()) {
427-
llvm::errs() << "Undefined symbol: " << undef->file().path()
428-
<< ": " << _ctx.demangle(undef->name())
429-
<< "\n";
427+
lld::errs() << "Undefined symbol: " << undef->file().path() << ": "
428+
<< _ctx.demangle(undef->name()) << "\n";
430429
}
431430
}
432431
if (!foundUndefines)
433432
return false;
434433
if (_ctx.printRemainingUndefines())
435-
llvm::errs() << "symbol(s) not found\n";
434+
lld::errs() << "symbol(s) not found\n";
436435
return true;
437436
}
438437

0 commit comments

Comments
 (0)