Skip to content

Commit 6caa8c9

Browse files
committed
llvm-foreach: print full command when failing
1 parent 53dca2d commit 6caa8c9

3 files changed

Lines changed: 100 additions & 36 deletions

File tree

llvm/test/tools/llvm-foreach/llvm-foreach-lin.ll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,12 @@
4646
; CHECK-PARALLEL-JOBS-DAG: [[SECOND:.+2.tgt]]
4747
; CHECK-PARALLEL-JOBS-DAG: [[THIRD:.+3.tgt]]
4848
; CHECK-PARALLEL-JOBS-DAG: [[FOURTH:.+4.tgt]]
49+
50+
; RUN: echo "%t1.tgt" > %t.fail.list
51+
; RUN: not llvm-foreach --in-replace="{}" --in-file-list=%t.fail.list -- false "{}" 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL-CMD
52+
; CHECK-FAIL-CMD: llvm-foreach: command failed with error code: 1
53+
; CHECK-FAIL-CMD-NEXT: llvm-foreach: command: "false" "{{.+1\.tgt}}"
54+
55+
; RUN: not llvm-foreach --in-replace="{}" --in-file-list=%t.fail.list -- llvm-foreach-command-does-not-exist "{}" 2>&1 | FileCheck %s --check-prefix=CHECK-NO-CMD
56+
; CHECK-NO-CMD: llvm-foreach: command failed:
57+
; CHECK-NO-CMD-NEXT: llvm-foreach: command: "llvm-foreach-command-does-not-exist" "{}"

llvm/test/tools/llvm-foreach/llvm-foreach-win.ll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,12 @@
4646
; CHECK-PARALLEL-JOBS-DAG: [[SECOND:.+2.tgt]]
4747
; CHECK-PARALLEL-JOBS-DAG: [[THIRD:.+3.tgt]]
4848
; CHECK-PARALLEL-JOBS-DAG: [[FOURTH:.+4.tgt]]
49+
50+
; RUN: echo "%t1.tgt" > %t.fail.list
51+
; RUN: not llvm-foreach --in-replace="{}" --in-file-list=%t.fail.list -- cmd /c exit 1 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL-CMD
52+
; CHECK-FAIL-CMD: llvm-foreach: command failed with error code: 1
53+
; CHECK-FAIL-CMD-NEXT: llvm-foreach: command: "cmd" "/c" "exit" "1"
54+
55+
; RUN: not llvm-foreach --in-replace="{}" --in-file-list=%t.fail.list -- llvm-foreach-command-does-not-exist "{}" 2>&1 | FileCheck %s --check-prefix=CHECK-NO-CMD
56+
; CHECK-NO-CMD: llvm-foreach: command failed:
57+
; CHECK-NO-CMD-NEXT: llvm-foreach: command: "llvm-foreach-command-does-not-exist" "{}"

llvm/tools/llvm-foreach/llvm-foreach.cpp

Lines changed: 82 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/Support/Program.h"
2020
#include "llvm/Support/SystemUtils.h"
2121
#include "llvm/Support/Threading.h"
22+
#include "llvm/Support/raw_ostream.h"
2223

2324
#include <list>
2425
#include <thread>
@@ -85,6 +86,35 @@ static cl::alias JobsInParallelShort{"j", cl::desc("Alias for --jobs"),
8586

8687
static constexpr int JobPollSleepIntervalMS = 100;
8788

89+
namespace {
90+
91+
struct RunningJob {
92+
sys::ProcessInfo Process;
93+
std::string Command;
94+
};
95+
96+
static std::string formatCommand(ArrayRef<StringRef> Args) {
97+
std::string Command;
98+
raw_string_ostream OS(Command);
99+
for (size_t I = 0; I < Args.size(); ++I) {
100+
if (I)
101+
OS << ' ';
102+
sys::printArg(OS, Args[I], /*Quote=*/true);
103+
}
104+
return Command;
105+
}
106+
107+
static void printCommandFailure(int ReturnCode, StringRef ErrMsg,
108+
StringRef Command) {
109+
errs() << "llvm-foreach: command failed";
110+
if (ReturnCode != 0)
111+
errs() << " with error code: " << ReturnCode;
112+
if (!ErrMsg.empty())
113+
errs() << ": " << ErrMsg;
114+
errs() << "\n"
115+
<< "llvm-foreach: command: " << Command << '\n';
116+
}
117+
88118
static void error(const Twine &Msg) {
89119
errs() << "llvm-foreach: " << Msg << '\n';
90120
exit(1);
@@ -99,19 +129,18 @@ static void error(std::error_code EC, const Twine &Prefix) {
99129
// Try to find a finished job with a non-blocking wait.
100130
// If no job found then sleep and repeat.
101131
// If found one job, removes it from Jobs and returns its exit code..
102-
static int waitForAnyJob(std::list<sys::ProcessInfo> &Jobs) {
132+
static int waitForAnyJob(std::list<RunningJob> &Jobs) {
103133
while (true) {
104134
std::string ErrMsg;
105135
for (auto It = Jobs.begin(); It != Jobs.end(); ++It) {
106136
// Non-blocking wait: returns Pid==0 if still running.
107137
sys::ProcessInfo WaitResult =
108-
sys::Wait(*It, /*SecondsToWait=*/0, &ErrMsg);
138+
sys::Wait(It->Process, /*SecondsToWait=*/0, &ErrMsg);
109139
if (WaitResult.Pid == 0)
110140
continue; // Job is in progress. Move on.
111141

112142
if (WaitResult.ReturnCode != 0)
113-
errs() << "llvm-foreach: failed with error code: "
114-
<< WaitResult.ReturnCode << ": " << ErrMsg << '\n';
143+
printCommandFailure(WaitResult.ReturnCode, ErrMsg, It->Command);
115144

116145
int RC = WaitResult.ReturnCode;
117146
Jobs.erase(It);
@@ -123,6 +152,8 @@ static int waitForAnyJob(std::list<sys::ProcessInfo> &Jobs) {
123152
}
124153
}
125154

155+
} // namespace
156+
126157
int main(int argc, char **argv) {
127158
cl::ParseCommandLineOptions(
128159
argc, argv,
@@ -164,23 +195,23 @@ int main(int argc, char **argv) {
164195
std::vector<ArgumentReplace> InReplaceArgs;
165196
ArgumentReplace OutReplaceArg;
166197
ArgumentReplace OutIncrementArg;
167-
for (size_t i = 1; i < Args.size(); ++i) {
198+
for (size_t I = 1; I < Args.size(); ++I) {
168199
for (auto &Replace : Replaces) {
169-
size_t ReplaceStart = Args[i].find(Replace);
200+
size_t ReplaceStart = Args[I].find(Replace);
170201
if (ReplaceStart != StringRef::npos)
171-
InReplaceArgs.push_back({i, ReplaceStart, Replace.size()});
202+
InReplaceArgs.push_back({I, ReplaceStart, Replace.size()});
172203
}
173204

174-
if (!OutReplace.empty() && Args[i].contains(OutReplace)) {
175-
size_t ReplaceStart = Args[i].find(OutReplace);
205+
if (!OutReplace.empty() && Args[I].contains(OutReplace)) {
206+
size_t ReplaceStart = Args[I].find(OutReplace);
176207
if (ReplaceStart != StringRef::npos)
177-
OutReplaceArg = {i, ReplaceStart, OutReplace.size()};
208+
OutReplaceArg = {I, ReplaceStart, OutReplace.size()};
178209
}
179210

180-
if (!OutIncrement.empty() && Args[i].contains(OutIncrement)) {
181-
size_t IncrementStart = Args[i].find(OutIncrement);
211+
if (!OutIncrement.empty() && Args[I].contains(OutIncrement)) {
212+
size_t IncrementStart = Args[I].find(OutIncrement);
182213
if (IncrementStart != StringRef::npos)
183-
OutIncrementArg = {i, IncrementStart, OutIncrement.size()};
214+
OutIncrementArg = {I, IncrementStart, OutIncrement.size()};
184215
}
185216
}
186217

@@ -190,18 +221,23 @@ int main(int argc, char **argv) {
190221
error("Couldn't find replace string for output in the command.");
191222

192223
// Make sure that specified program exists, emit an error if not.
193-
std::string Prog =
194-
ExitOnErr(errorOrToExpected(sys::findProgramByName(Args[0])));
224+
ErrorOr<std::string> ProgOrErr = sys::findProgramByName(Args[0]);
225+
if (!ProgOrErr) {
226+
printCommandFailure(/*ReturnCode=*/0, ProgOrErr.getError().message(),
227+
formatCommand(Args));
228+
return 1;
229+
}
230+
std::string Prog = *ProgOrErr;
195231

196232
std::vector<std::vector<std::string>> FileLists(LineIterators.size());
197233
size_t PrevNumOfLines = 0;
198-
for (size_t i = 0; i < FileLists.size(); ++i) {
199-
for (; !LineIterators[i].is_at_eof(); ++LineIterators[i]) {
200-
FileLists[i].push_back(LineIterators[i]->str());
234+
for (size_t I = 0; I < FileLists.size(); ++I) {
235+
for (; !LineIterators[I].is_at_eof(); ++LineIterators[I]) {
236+
FileLists[I].push_back(LineIterators[I]->str());
201237
}
202-
if (i != 0 && FileLists[i].size() != PrevNumOfLines)
238+
if (I != 0 && FileLists[I].size() != PrevNumOfLines)
203239
error("All input file lists must have same number of lines!");
204-
PrevNumOfLines = FileLists[i].size();
240+
PrevNumOfLines = FileLists[I].size();
205241
}
206242

207243
if (!JobsInParallel)
@@ -224,17 +260,17 @@ int main(int argc, char **argv) {
224260
std::string IncOutArg;
225261
std::vector<std::string> ResInArgs(InReplaceArgs.size());
226262
std::string ResFileList = "";
227-
std::list<sys::ProcessInfo> JobsSubmitted;
228-
for (size_t j = 0; j != FileLists[0].size(); ++j) {
229-
for (size_t i = 0; i < InReplaceArgs.size(); ++i) {
230-
ArgumentReplace CurReplace = InReplaceArgs[i];
263+
std::list<RunningJob> JobsSubmitted;
264+
for (size_t J = 0; J != FileLists[0].size(); ++J) {
265+
for (size_t I = 0; I < InReplaceArgs.size(); ++I) {
266+
ArgumentReplace CurReplace = InReplaceArgs[I];
231267
std::string OriginalString = InputCommandArgs[CurReplace.ArgNum];
232-
ResInArgs[i] = (Twine(OriginalString.substr(0, CurReplace.Start)) +
233-
Twine(FileLists[i][j]) +
268+
ResInArgs[I] = (Twine(OriginalString.substr(0, CurReplace.Start)) +
269+
Twine(FileLists[I][J]) +
234270
Twine(OriginalString.substr(CurReplace.Start +
235271
CurReplace.ReplaceLen)))
236272
.str();
237-
Args[CurReplace.ArgNum] = ResInArgs[i];
273+
Args[CurReplace.ArgNum] = ResInArgs[I];
238274
}
239275

240276
SmallString<128> Path;
@@ -271,8 +307,8 @@ int main(int argc, char **argv) {
271307
if (!OutIncrement.empty()) {
272308
// Name the file by adding the current file list index to the name.
273309
IncOutArg = InputCommandArgs[OutIncrementArg.ArgNum];
274-
if (j > 0)
275-
IncOutArg += ("_" + Twine(j)).str();
310+
if (J > 0)
311+
IncOutArg += ("_" + Twine(J)).str();
276312
Args[OutIncrementArg.ArgNum] = IncOutArg;
277313
}
278314
// Do not start execution of a new job until previous one(s) are finished,
@@ -282,20 +318,30 @@ int main(int argc, char **argv) {
282318
Res = ReturnCode;
283319
}
284320

285-
JobsSubmitted.emplace_back(
286-
sys::ExecuteNoWait(Prog, Args, /*Env=*/std::nullopt,
287-
/*Redirects=*/{}, /*MemoryLimit=*/0));
321+
std::string CommandToRun = formatCommand(Args);
322+
std::string ErrMsg;
323+
bool ExecutionFailed = false;
324+
sys::ProcessInfo PI =
325+
sys::ExecuteNoWait(Prog, Args, /*Env=*/std::nullopt, /*Redirects=*/{},
326+
/*MemoryLimit=*/0, &ErrMsg, &ExecutionFailed);
327+
if (ExecutionFailed) {
328+
printCommandFailure(/*ReturnCode=*/0, ErrMsg, CommandToRun);
329+
Res = 1;
330+
continue;
331+
}
332+
333+
JobsSubmitted.emplace_back(RunningJob{PI, std::move(CommandToRun)});
288334
}
289335

290336
// Wait for all commands to be executed (blocking wait, no sleep needed).
291337
while (!JobsSubmitted.empty()) {
292338
std::string ErrMsg;
293-
sys::ProcessInfo WaitResult = sys::Wait(
294-
JobsSubmitted.front(), /*SecondsToWait=*/std::nullopt, &ErrMsg);
339+
RunningJob &Job = JobsSubmitted.front();
340+
sys::ProcessInfo WaitResult =
341+
sys::Wait(Job.Process, /*SecondsToWait=*/std::nullopt, &ErrMsg);
295342
assert(WaitResult.Pid && "sys::Wait should return positive pid");
296343
if (WaitResult.ReturnCode != 0) {
297-
errs() << "llvm-foreach: failed with error code: "
298-
<< WaitResult.ReturnCode << ": " << ErrMsg << '\n';
344+
printCommandFailure(WaitResult.ReturnCode, ErrMsg, Job.Command);
299345
Res = WaitResult.ReturnCode;
300346
}
301347

0 commit comments

Comments
 (0)