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
8687static 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+
88118static 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+
126157int 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