ToolRunner.cpp revision 207618
1//===-- ToolRunner.cpp ----------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the interfaces described in the ToolRunner.h file.
11//
12//===----------------------------------------------------------------------===//
13
14#define DEBUG_TYPE "toolrunner"
15#include "ToolRunner.h"
16#include "llvm/System/Program.h"
17#include "llvm/Support/CommandLine.h"
18#include "llvm/Support/Debug.h"
19#include "llvm/Support/FileUtilities.h"
20#include "llvm/Support/raw_ostream.h"
21#include "llvm/Config/config.h"   // for HAVE_LINK_R
22#include <fstream>
23#include <sstream>
24using namespace llvm;
25
26namespace llvm {
27  cl::opt<bool>
28  SaveTemps("save-temps", cl::init(false), cl::desc("Save temporary files"));
29}
30
31namespace {
32  cl::opt<std::string>
33  RemoteClient("remote-client",
34               cl::desc("Remote execution client (rsh/ssh)"));
35
36  cl::opt<std::string>
37  RemoteHost("remote-host",
38             cl::desc("Remote execution (rsh/ssh) host"));
39
40  cl::opt<std::string>
41  RemotePort("remote-port",
42             cl::desc("Remote execution (rsh/ssh) port"));
43
44  cl::opt<std::string>
45  RemoteUser("remote-user",
46             cl::desc("Remote execution (rsh/ssh) user id"));
47
48  cl::opt<std::string>
49  RemoteExtra("remote-extra-options",
50          cl::desc("Remote execution (rsh/ssh) extra options"));
51}
52
53/// RunProgramWithTimeout - This function provides an alternate interface
54/// to the sys::Program::ExecuteAndWait interface.
55/// @see sys::Program::ExecuteAndWait
56static int RunProgramWithTimeout(const sys::Path &ProgramPath,
57                                 const char **Args,
58                                 const sys::Path &StdInFile,
59                                 const sys::Path &StdOutFile,
60                                 const sys::Path &StdErrFile,
61                                 unsigned NumSeconds = 0,
62                                 unsigned MemoryLimit = 0) {
63  const sys::Path* redirects[3];
64  redirects[0] = &StdInFile;
65  redirects[1] = &StdOutFile;
66  redirects[2] = &StdErrFile;
67
68#if 0 // For debug purposes
69  {
70    errs() << "RUN:";
71    for (unsigned i = 0; Args[i]; ++i)
72      errs() << " " << Args[i];
73    errs() << "\n";
74  }
75#endif
76
77  return
78    sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects,
79                                 NumSeconds, MemoryLimit);
80}
81
82/// RunProgramRemotelyWithTimeout - This function runs the given program
83/// remotely using the given remote client and the sys::Program::ExecuteAndWait.
84/// Returns the remote program exit code or reports a remote client error if it
85/// fails. Remote client is required to return 255 if it failed or program exit
86/// code otherwise.
87/// @see sys::Program::ExecuteAndWait
88static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath,
89                                         const char **Args,
90                                         const sys::Path &StdInFile,
91                                         const sys::Path &StdOutFile,
92                                         const sys::Path &StdErrFile,
93                                         unsigned NumSeconds = 0,
94                                         unsigned MemoryLimit = 0) {
95  const sys::Path* redirects[3];
96  redirects[0] = &StdInFile;
97  redirects[1] = &StdOutFile;
98  redirects[2] = &StdErrFile;
99
100#if 0 // For debug purposes
101  {
102    errs() << "RUN:";
103    for (unsigned i = 0; Args[i]; ++i)
104      errs() << " " << Args[i];
105    errs() << "\n";
106  }
107#endif
108
109  // Run the program remotely with the remote client
110  int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args,
111                                 0, redirects, NumSeconds, MemoryLimit);
112
113  // Has the remote client fail?
114  if (255 == ReturnCode) {
115    std::ostringstream OS;
116    OS << "\nError running remote client:\n ";
117    for (const char **Arg = Args; *Arg; ++Arg)
118      OS << " " << *Arg;
119    OS << "\n";
120
121    // The error message is in the output file, let's print it out from there.
122    std::ifstream ErrorFile(StdOutFile.c_str());
123    if (ErrorFile) {
124      std::copy(std::istreambuf_iterator<char>(ErrorFile),
125                std::istreambuf_iterator<char>(),
126                std::ostreambuf_iterator<char>(OS));
127      ErrorFile.close();
128    }
129
130    errs() << OS;
131  }
132
133  return ReturnCode;
134}
135
136static std::string ProcessFailure(sys::Path ProgPath, const char** Args) {
137  std::ostringstream OS;
138  OS << "\nError running tool:\n ";
139  for (const char **Arg = Args; *Arg; ++Arg)
140    OS << " " << *Arg;
141  OS << "\n";
142
143  // Rerun the compiler, capturing any error messages to print them.
144  sys::Path ErrorFilename("bugpoint.program_error_messages");
145  std::string ErrMsg;
146  if (ErrorFilename.makeUnique(true, &ErrMsg)) {
147    errs() << "Error making unique filename: " << ErrMsg << "\n";
148    exit(1);
149  }
150  RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename,
151                        ErrorFilename); // FIXME: check return code ?
152
153  // Print out the error messages generated by GCC if possible...
154  std::ifstream ErrorFile(ErrorFilename.c_str());
155  if (ErrorFile) {
156    std::copy(std::istreambuf_iterator<char>(ErrorFile),
157              std::istreambuf_iterator<char>(),
158              std::ostreambuf_iterator<char>(OS));
159    ErrorFile.close();
160  }
161
162  ErrorFilename.eraseFromDisk();
163  return OS.str();
164}
165
166//===---------------------------------------------------------------------===//
167// LLI Implementation of AbstractIntepreter interface
168//
169namespace {
170  class LLI : public AbstractInterpreter {
171    std::string LLIPath;          // The path to the LLI executable
172    std::vector<std::string> ToolArgs; // Args to pass to LLI
173  public:
174    LLI(const std::string &Path, const std::vector<std::string> *Args)
175      : LLIPath(Path) {
176      ToolArgs.clear ();
177      if (Args) { ToolArgs = *Args; }
178    }
179
180    virtual int ExecuteProgram(const std::string &Bitcode,
181                               const std::vector<std::string> &Args,
182                               const std::string &InputFile,
183                               const std::string &OutputFile,
184                               std::string *Error,
185                               const std::vector<std::string> &GCCArgs,
186                               const std::vector<std::string> &SharedLibs =
187                               std::vector<std::string>(),
188                               unsigned Timeout = 0,
189                               unsigned MemoryLimit = 0);
190  };
191}
192
193int LLI::ExecuteProgram(const std::string &Bitcode,
194                        const std::vector<std::string> &Args,
195                        const std::string &InputFile,
196                        const std::string &OutputFile,
197                        std::string *Error,
198                        const std::vector<std::string> &GCCArgs,
199                        const std::vector<std::string> &SharedLibs,
200                        unsigned Timeout,
201                        unsigned MemoryLimit) {
202  std::vector<const char*> LLIArgs;
203  LLIArgs.push_back(LLIPath.c_str());
204  LLIArgs.push_back("-force-interpreter=true");
205
206  for (std::vector<std::string>::const_iterator i = SharedLibs.begin(), e = SharedLibs.end(); i != e; ++i) {
207    LLIArgs.push_back("-load");
208    LLIArgs.push_back((*i).c_str());
209  }
210
211  // Add any extra LLI args.
212  for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
213    LLIArgs.push_back(ToolArgs[i].c_str());
214
215  LLIArgs.push_back(Bitcode.c_str());
216  // Add optional parameters to the running program from Argv
217  for (unsigned i=0, e = Args.size(); i != e; ++i)
218    LLIArgs.push_back(Args[i].c_str());
219  LLIArgs.push_back(0);
220
221  outs() << "<lli>"; outs().flush();
222  DEBUG(errs() << "\nAbout to run:\t";
223        for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i)
224          errs() << " " << LLIArgs[i];
225        errs() << "\n";
226        );
227  return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0],
228      sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
229      Timeout, MemoryLimit);
230}
231
232// LLI create method - Try to find the LLI executable
233AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0,
234                                                    std::string &Message,
235                                     const std::vector<std::string> *ToolArgs) {
236  std::string LLIPath =
237    FindExecutable("lli", Argv0, (void *)(intptr_t)&createLLI).str();
238  if (!LLIPath.empty()) {
239    Message = "Found lli: " + LLIPath + "\n";
240    return new LLI(LLIPath, ToolArgs);
241  }
242
243  Message = "Cannot find `lli' in executable directory or PATH!\n";
244  return 0;
245}
246
247//===---------------------------------------------------------------------===//
248// Custom execution command implementation of AbstractIntepreter interface
249//
250// Allows using a custom command for executing the bitcode, thus allows,
251// for example, to invoke a cross compiler for code generation followed by
252// a simulator that executes the generated binary.
253namespace {
254  class CustomExecutor : public AbstractInterpreter {
255    std::string ExecutionCommand;
256    std::vector<std::string> ExecutorArgs;
257  public:
258    CustomExecutor(
259      const std::string &ExecutionCmd, std::vector<std::string> ExecArgs) :
260      ExecutionCommand(ExecutionCmd), ExecutorArgs(ExecArgs) {}
261
262    virtual int ExecuteProgram(const std::string &Bitcode,
263                               const std::vector<std::string> &Args,
264                               const std::string &InputFile,
265                               const std::string &OutputFile,
266                               std::string *Error,
267                               const std::vector<std::string> &GCCArgs,
268                               const std::vector<std::string> &SharedLibs =
269                                 std::vector<std::string>(),
270                               unsigned Timeout = 0,
271                               unsigned MemoryLimit = 0);
272  };
273}
274
275int CustomExecutor::ExecuteProgram(const std::string &Bitcode,
276                        const std::vector<std::string> &Args,
277                        const std::string &InputFile,
278                        const std::string &OutputFile,
279                        std::string *Error,
280                        const std::vector<std::string> &GCCArgs,
281                        const std::vector<std::string> &SharedLibs,
282                        unsigned Timeout,
283                        unsigned MemoryLimit) {
284
285  std::vector<const char*> ProgramArgs;
286  ProgramArgs.push_back(ExecutionCommand.c_str());
287
288  for (std::size_t i = 0; i < ExecutorArgs.size(); ++i)
289    ProgramArgs.push_back(ExecutorArgs.at(i).c_str());
290  ProgramArgs.push_back(Bitcode.c_str());
291  ProgramArgs.push_back(0);
292
293  // Add optional parameters to the running program from Argv
294  for (unsigned i = 0, e = Args.size(); i != e; ++i)
295    ProgramArgs.push_back(Args[i].c_str());
296
297  return RunProgramWithTimeout(
298    sys::Path(ExecutionCommand),
299    &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile),
300    sys::Path(OutputFile), Timeout, MemoryLimit);
301}
302
303// Custom execution environment create method, takes the execution command
304// as arguments
305AbstractInterpreter *AbstractInterpreter::createCustom(
306                    std::string &Message,
307                    const std::string &ExecCommandLine) {
308
309  std::string Command = "";
310  std::vector<std::string> Args;
311  std::string delimiters = " ";
312
313  // Tokenize the ExecCommandLine to the command and the args to allow
314  // defining a full command line as the command instead of just the
315  // executed program. We cannot just pass the whole string after the command
316  // as a single argument because then program sees only a single
317  // command line argument (with spaces in it: "foo bar" instead
318  // of "foo" and "bar").
319
320  // code borrowed from:
321  // http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
322  std::string::size_type lastPos =
323    ExecCommandLine.find_first_not_of(delimiters, 0);
324  std::string::size_type pos =
325    ExecCommandLine.find_first_of(delimiters, lastPos);
326
327  while (std::string::npos != pos || std::string::npos != lastPos) {
328    std::string token = ExecCommandLine.substr(lastPos, pos - lastPos);
329    if (Command == "")
330       Command = token;
331    else
332       Args.push_back(token);
333    // Skip delimiters.  Note the "not_of"
334    lastPos = ExecCommandLine.find_first_not_of(delimiters, pos);
335    // Find next "non-delimiter"
336    pos = ExecCommandLine.find_first_of(delimiters, lastPos);
337  }
338
339  std::string CmdPath = sys::Program::FindProgramByName(Command).str();
340  if (CmdPath.empty()) {
341    Message =
342      std::string("Cannot find '") + Command +
343      "' in executable directory or PATH!\n";
344    return 0;
345  }
346
347  Message = "Found command in: " + CmdPath + "\n";
348
349  return new CustomExecutor(CmdPath, Args);
350}
351
352//===----------------------------------------------------------------------===//
353// LLC Implementation of AbstractIntepreter interface
354//
355GCC::FileType LLC::OutputCode(const std::string &Bitcode,
356                              sys::Path &OutputAsmFile, std::string &Error) {
357  const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s");
358  sys::Path uniqueFile(Bitcode + Suffix);
359  std::string ErrMsg;
360  if (uniqueFile.makeUnique(true, &ErrMsg)) {
361    errs() << "Error making unique filename: " << ErrMsg << "\n";
362    exit(1);
363  }
364  OutputAsmFile = uniqueFile;
365  std::vector<const char *> LLCArgs;
366  LLCArgs.push_back(LLCPath.c_str());
367
368  // Add any extra LLC args.
369  for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
370    LLCArgs.push_back(ToolArgs[i].c_str());
371
372  LLCArgs.push_back("-o");
373  LLCArgs.push_back(OutputAsmFile.c_str()); // Output to the Asm file
374  LLCArgs.push_back(Bitcode.c_str());      // This is the input bitcode
375
376  if (UseIntegratedAssembler)
377    LLCArgs.push_back("-filetype=obj");
378
379  LLCArgs.push_back (0);
380
381  outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>");
382  outs().flush();
383  DEBUG(errs() << "\nAbout to run:\t";
384        for (unsigned i = 0, e = LLCArgs.size()-1; i != e; ++i)
385          errs() << " " << LLCArgs[i];
386        errs() << "\n";
387        );
388  if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0],
389                            sys::Path(), sys::Path(), sys::Path()))
390    Error = ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]);
391  return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile;
392}
393
394void LLC::compileProgram(const std::string &Bitcode, std::string *Error) {
395  sys::Path OutputAsmFile;
396  OutputCode(Bitcode, OutputAsmFile, *Error);
397  OutputAsmFile.eraseFromDisk();
398}
399
400int LLC::ExecuteProgram(const std::string &Bitcode,
401                        const std::vector<std::string> &Args,
402                        const std::string &InputFile,
403                        const std::string &OutputFile,
404                        std::string *Error,
405                        const std::vector<std::string> &ArgsForGCC,
406                        const std::vector<std::string> &SharedLibs,
407                        unsigned Timeout,
408                        unsigned MemoryLimit) {
409
410  sys::Path OutputAsmFile;
411  GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error);
412  FileRemover OutFileRemover(OutputAsmFile, !SaveTemps);
413
414  std::vector<std::string> GCCArgs(ArgsForGCC);
415  GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end());
416  GCCArgs.insert(GCCArgs.end(), gccArgs.begin(), gccArgs.end());
417
418  // Assuming LLC worked, compile the result with GCC and run it.
419  return gcc->ExecuteProgram(OutputAsmFile.str(), Args, FileKind,
420                             InputFile, OutputFile, Error, GCCArgs,
421                             Timeout, MemoryLimit);
422}
423
424/// createLLC - Try to find the LLC executable
425///
426LLC *AbstractInterpreter::createLLC(const char *Argv0,
427                                    std::string &Message,
428                                    const std::vector<std::string> *Args,
429                                    const std::vector<std::string> *GCCArgs,
430                                    bool UseIntegratedAssembler) {
431  std::string LLCPath =
432    FindExecutable("llc", Argv0, (void *)(intptr_t)&createLLC).str();
433  if (LLCPath.empty()) {
434    Message = "Cannot find `llc' in executable directory or PATH!\n";
435    return 0;
436  }
437
438  Message = "Found llc: " + LLCPath + "\n";
439  GCC *gcc = GCC::create(Message, GCCArgs);
440  if (!gcc) {
441    errs() << Message << "\n";
442    exit(1);
443  }
444  return new LLC(LLCPath, gcc, Args, GCCArgs, UseIntegratedAssembler);
445}
446
447//===---------------------------------------------------------------------===//
448// JIT Implementation of AbstractIntepreter interface
449//
450namespace {
451  class JIT : public AbstractInterpreter {
452    std::string LLIPath;          // The path to the LLI executable
453    std::vector<std::string> ToolArgs; // Args to pass to LLI
454  public:
455    JIT(const std::string &Path, const std::vector<std::string> *Args)
456      : LLIPath(Path) {
457      ToolArgs.clear ();
458      if (Args) { ToolArgs = *Args; }
459    }
460
461    virtual int ExecuteProgram(const std::string &Bitcode,
462                               const std::vector<std::string> &Args,
463                               const std::string &InputFile,
464                               const std::string &OutputFile,
465                               std::string *Error,
466                               const std::vector<std::string> &GCCArgs =
467                                 std::vector<std::string>(),
468                               const std::vector<std::string> &SharedLibs =
469                                 std::vector<std::string>(),
470                               unsigned Timeout = 0,
471                               unsigned MemoryLimit = 0);
472  };
473}
474
475int JIT::ExecuteProgram(const std::string &Bitcode,
476                        const std::vector<std::string> &Args,
477                        const std::string &InputFile,
478                        const std::string &OutputFile,
479                        std::string *Error,
480                        const std::vector<std::string> &GCCArgs,
481                        const std::vector<std::string> &SharedLibs,
482                        unsigned Timeout,
483                        unsigned MemoryLimit) {
484  // Construct a vector of parameters, incorporating those from the command-line
485  std::vector<const char*> JITArgs;
486  JITArgs.push_back(LLIPath.c_str());
487  JITArgs.push_back("-force-interpreter=false");
488
489  // Add any extra LLI args.
490  for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
491    JITArgs.push_back(ToolArgs[i].c_str());
492
493  for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {
494    JITArgs.push_back("-load");
495    JITArgs.push_back(SharedLibs[i].c_str());
496  }
497  JITArgs.push_back(Bitcode.c_str());
498  // Add optional parameters to the running program from Argv
499  for (unsigned i=0, e = Args.size(); i != e; ++i)
500    JITArgs.push_back(Args[i].c_str());
501  JITArgs.push_back(0);
502
503  outs() << "<jit>"; outs().flush();
504  DEBUG(errs() << "\nAbout to run:\t";
505        for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i)
506          errs() << " " << JITArgs[i];
507        errs() << "\n";
508        );
509  DEBUG(errs() << "\nSending output to " << OutputFile << "\n");
510  return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0],
511      sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
512      Timeout, MemoryLimit);
513}
514
515/// createJIT - Try to find the LLI executable
516///
517AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0,
518                   std::string &Message, const std::vector<std::string> *Args) {
519  std::string LLIPath =
520    FindExecutable("lli", Argv0, (void *)(intptr_t)&createJIT).str();
521  if (!LLIPath.empty()) {
522    Message = "Found lli: " + LLIPath + "\n";
523    return new JIT(LLIPath, Args);
524  }
525
526  Message = "Cannot find `lli' in executable directory or PATH!\n";
527  return 0;
528}
529
530GCC::FileType CBE::OutputCode(const std::string &Bitcode,
531                              sys::Path &OutputCFile, std::string &Error) {
532  sys::Path uniqueFile(Bitcode+".cbe.c");
533  std::string ErrMsg;
534  if (uniqueFile.makeUnique(true, &ErrMsg)) {
535    errs() << "Error making unique filename: " << ErrMsg << "\n";
536    exit(1);
537  }
538  OutputCFile = uniqueFile;
539  std::vector<const char *> LLCArgs;
540  LLCArgs.push_back(LLCPath.c_str());
541
542  // Add any extra LLC args.
543  for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
544    LLCArgs.push_back(ToolArgs[i].c_str());
545
546  LLCArgs.push_back("-o");
547  LLCArgs.push_back(OutputCFile.c_str());   // Output to the C file
548  LLCArgs.push_back("-march=c");            // Output C language
549  LLCArgs.push_back(Bitcode.c_str());      // This is the input bitcode
550  LLCArgs.push_back(0);
551
552  outs() << "<cbe>"; outs().flush();
553  DEBUG(errs() << "\nAbout to run:\t";
554        for (unsigned i = 0, e = LLCArgs.size()-1; i != e; ++i)
555          errs() << " " << LLCArgs[i];
556        errs() << "\n";
557        );
558  if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(),
559                            sys::Path()))
560    Error = ProcessFailure(LLCPath, &LLCArgs[0]);
561  return GCC::CFile;
562}
563
564void CBE::compileProgram(const std::string &Bitcode, std::string *Error) {
565  sys::Path OutputCFile;
566  OutputCode(Bitcode, OutputCFile, *Error);
567  OutputCFile.eraseFromDisk();
568}
569
570int CBE::ExecuteProgram(const std::string &Bitcode,
571                        const std::vector<std::string> &Args,
572                        const std::string &InputFile,
573                        const std::string &OutputFile,
574                        std::string *Error,
575                        const std::vector<std::string> &ArgsForGCC,
576                        const std::vector<std::string> &SharedLibs,
577                        unsigned Timeout,
578                        unsigned MemoryLimit) {
579  sys::Path OutputCFile;
580  OutputCode(Bitcode, OutputCFile, *Error);
581
582  FileRemover CFileRemove(OutputCFile, !SaveTemps);
583
584  std::vector<std::string> GCCArgs(ArgsForGCC);
585  GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end());
586
587  return gcc->ExecuteProgram(OutputCFile.str(), Args, GCC::CFile,
588                             InputFile, OutputFile, Error, GCCArgs,
589                             Timeout, MemoryLimit);
590}
591
592/// createCBE - Try to find the 'llc' executable
593///
594CBE *AbstractInterpreter::createCBE(const char *Argv0,
595                                    std::string &Message,
596                                    const std::vector<std::string> *Args,
597                                    const std::vector<std::string> *GCCArgs) {
598  sys::Path LLCPath =
599    FindExecutable("llc", Argv0, (void *)(intptr_t)&createCBE);
600  if (LLCPath.isEmpty()) {
601    Message =
602      "Cannot find `llc' in executable directory or PATH!\n";
603    return 0;
604  }
605
606  Message = "Found llc: " + LLCPath.str() + "\n";
607  GCC *gcc = GCC::create(Message, GCCArgs);
608  if (!gcc) {
609    errs() << Message << "\n";
610    exit(1);
611  }
612  return new CBE(LLCPath, gcc, Args);
613}
614
615//===---------------------------------------------------------------------===//
616// GCC abstraction
617//
618
619static bool IsARMArchitecture(std::vector<std::string> Args) {
620  for (std::vector<std::string>::const_iterator
621         I = Args.begin(), E = Args.end(); I != E; ++I) {
622    StringRef S(*I);
623    if (!S.equals_lower("-arch")) {
624      ++I;
625      if (I != E && !S.substr(0, strlen("arm")).equals_lower("arm"))
626        return true;
627    }
628  }
629
630  return false;
631}
632
633int GCC::ExecuteProgram(const std::string &ProgramFile,
634                        const std::vector<std::string> &Args,
635                        FileType fileType,
636                        const std::string &InputFile,
637                        const std::string &OutputFile,
638                        std::string *Error,
639                        const std::vector<std::string> &ArgsForGCC,
640                        unsigned Timeout,
641                        unsigned MemoryLimit) {
642  std::vector<const char*> GCCArgs;
643
644  GCCArgs.push_back(GCCPath.c_str());
645
646  if (TargetTriple.getArch() == Triple::x86)
647    GCCArgs.push_back("-m32");
648
649  for (std::vector<std::string>::const_iterator
650         I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I)
651    GCCArgs.push_back(I->c_str());
652
653  // Specify -x explicitly in case the extension is wonky
654  if (fileType != ObjectFile) {
655    GCCArgs.push_back("-x");
656    if (fileType == CFile) {
657      GCCArgs.push_back("c");
658      GCCArgs.push_back("-fno-strict-aliasing");
659    } else {
660      GCCArgs.push_back("assembler");
661
662      // For ARM architectures we don't want this flag. bugpoint isn't
663      // explicitly told what architecture it is working on, so we get
664      // it from gcc flags
665      if ((TargetTriple.getOS() == Triple::Darwin) &&
666          !IsARMArchitecture(ArgsForGCC))
667        GCCArgs.push_back("-force_cpusubtype_ALL");
668    }
669  }
670
671  GCCArgs.push_back(ProgramFile.c_str());  // Specify the input filename.
672
673  GCCArgs.push_back("-x");
674  GCCArgs.push_back("none");
675  GCCArgs.push_back("-o");
676  sys::Path OutputBinary (ProgramFile+".gcc.exe");
677  std::string ErrMsg;
678  if (OutputBinary.makeUnique(true, &ErrMsg)) {
679    errs() << "Error making unique filename: " << ErrMsg << "\n";
680    exit(1);
681  }
682  GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
683
684  // Add any arguments intended for GCC. We locate them here because this is
685  // most likely -L and -l options that need to come before other libraries but
686  // after the source. Other options won't be sensitive to placement on the
687  // command line, so this should be safe.
688  for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i)
689    GCCArgs.push_back(ArgsForGCC[i].c_str());
690
691  GCCArgs.push_back("-lm");                // Hard-code the math library...
692  GCCArgs.push_back("-O2");                // Optimize the program a bit...
693#if defined (HAVE_LINK_R)
694  GCCArgs.push_back("-Wl,-R.");            // Search this dir for .so files
695#endif
696  if (TargetTriple.getArch() == Triple::sparc)
697    GCCArgs.push_back("-mcpu=v9");
698  GCCArgs.push_back(0);                    // NULL terminator
699
700  outs() << "<gcc>"; outs().flush();
701  DEBUG(errs() << "\nAbout to run:\t";
702        for (unsigned i = 0, e = GCCArgs.size()-1; i != e; ++i)
703          errs() << " " << GCCArgs[i];
704        errs() << "\n";
705        );
706  if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(),
707        sys::Path())) {
708    *Error = ProcessFailure(GCCPath, &GCCArgs[0]);
709    return -1;
710  }
711
712  std::vector<const char*> ProgramArgs;
713
714  if (RemoteClientPath.isEmpty())
715    ProgramArgs.push_back(OutputBinary.c_str());
716  else {
717    ProgramArgs.push_back(RemoteClientPath.c_str());
718    ProgramArgs.push_back(RemoteHost.c_str());
719    if (!RemoteUser.empty()) {
720      ProgramArgs.push_back("-l");
721      ProgramArgs.push_back(RemoteUser.c_str());
722    }
723    if (!RemotePort.empty()) {
724      ProgramArgs.push_back("-p");
725      ProgramArgs.push_back(RemotePort.c_str());
726    }
727    if (!RemoteExtra.empty()) {
728      ProgramArgs.push_back(RemoteExtra.c_str());
729    }
730
731    // Full path to the binary. We need to cd to the exec directory because
732    // there is a dylib there that the exec expects to find in the CWD
733    char* env_pwd = getenv("PWD");
734    std::string Exec = "cd ";
735    Exec += env_pwd;
736    Exec += "; ./";
737    Exec += OutputBinary.c_str();
738    ProgramArgs.push_back(Exec.c_str());
739  }
740
741  // Add optional parameters to the running program from Argv
742  for (unsigned i = 0, e = Args.size(); i != e; ++i)
743    ProgramArgs.push_back(Args[i].c_str());
744  ProgramArgs.push_back(0);                // NULL terminator
745
746  // Now that we have a binary, run it!
747  outs() << "<program>"; outs().flush();
748  DEBUG(errs() << "\nAbout to run:\t";
749        for (unsigned i = 0, e = ProgramArgs.size()-1; i != e; ++i)
750          errs() << " " << ProgramArgs[i];
751        errs() << "\n";
752        );
753
754  FileRemover OutputBinaryRemover(OutputBinary, !SaveTemps);
755
756  if (RemoteClientPath.isEmpty()) {
757    DEBUG(errs() << "<run locally>");
758    return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
759        sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
760        Timeout, MemoryLimit);
761  } else {
762    outs() << "<run remotely>"; outs().flush();
763    return RunProgramRemotelyWithTimeout(sys::Path(RemoteClientPath),
764        &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile),
765        sys::Path(OutputFile), Timeout, MemoryLimit);
766  }
767}
768
769int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
770                          std::string &OutputFile,
771                          const std::vector<std::string> &ArgsForGCC,
772                          std::string &Error) {
773  sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT);
774  std::string ErrMsg;
775  if (uniqueFilename.makeUnique(true, &ErrMsg)) {
776    errs() << "Error making unique filename: " << ErrMsg << "\n";
777    exit(1);
778  }
779  OutputFile = uniqueFilename.str();
780
781  std::vector<const char*> GCCArgs;
782
783  GCCArgs.push_back(GCCPath.c_str());
784
785  if (TargetTriple.getArch() == Triple::x86)
786    GCCArgs.push_back("-m32");
787
788  for (std::vector<std::string>::const_iterator
789         I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I)
790    GCCArgs.push_back(I->c_str());
791
792  // Compile the C/asm file into a shared object
793  if (fileType != ObjectFile) {
794    GCCArgs.push_back("-x");
795    GCCArgs.push_back(fileType == AsmFile ? "assembler" : "c");
796  }
797  GCCArgs.push_back("-fno-strict-aliasing");
798  GCCArgs.push_back(InputFile.c_str());   // Specify the input filename.
799  GCCArgs.push_back("-x");
800  GCCArgs.push_back("none");
801  if (TargetTriple.getArch() == Triple::sparc)
802    GCCArgs.push_back("-G");       // Compile a shared library, `-G' for Sparc
803  else if (TargetTriple.getOS() == Triple::Darwin) {
804    // link all source files into a single module in data segment, rather than
805    // generating blocks. dynamic_lookup requires that you set
806    // MACOSX_DEPLOYMENT_TARGET=10.3 in your env.  FIXME: it would be better for
807    // bugpoint to just pass that in the environment of GCC.
808    GCCArgs.push_back("-single_module");
809    GCCArgs.push_back("-dynamiclib");   // `-dynamiclib' for MacOS X/PowerPC
810    GCCArgs.push_back("-undefined");
811    GCCArgs.push_back("dynamic_lookup");
812  } else
813    GCCArgs.push_back("-shared");  // `-shared' for Linux/X86, maybe others
814
815  if ((TargetTriple.getArch() == Triple::alpha) ||
816      (TargetTriple.getArch() == Triple::x86_64))
817    GCCArgs.push_back("-fPIC");   // Requires shared objs to contain PIC
818
819  if (TargetTriple.getArch() == Triple::sparc)
820    GCCArgs.push_back("-mcpu=v9");
821
822  GCCArgs.push_back("-o");
823  GCCArgs.push_back(OutputFile.c_str()); // Output to the right filename.
824  GCCArgs.push_back("-O2");              // Optimize the program a bit.
825
826
827
828  // Add any arguments intended for GCC. We locate them here because this is
829  // most likely -L and -l options that need to come before other libraries but
830  // after the source. Other options won't be sensitive to placement on the
831  // command line, so this should be safe.
832  for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i)
833    GCCArgs.push_back(ArgsForGCC[i].c_str());
834  GCCArgs.push_back(0);                    // NULL terminator
835
836
837
838  outs() << "<gcc>"; outs().flush();
839  DEBUG(errs() << "\nAbout to run:\t";
840        for (unsigned i = 0, e = GCCArgs.size()-1; i != e; ++i)
841          errs() << " " << GCCArgs[i];
842        errs() << "\n";
843        );
844  if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(),
845                            sys::Path())) {
846    Error = ProcessFailure(GCCPath, &GCCArgs[0]);
847    return 1;
848  }
849  return 0;
850}
851
852/// create - Try to find the `gcc' executable
853///
854GCC *GCC::create(std::string &Message,
855                 const std::vector<std::string> *Args) {
856  sys::Path GCCPath = sys::Program::FindProgramByName("gcc");
857  if (GCCPath.isEmpty()) {
858    Message = "Cannot find `gcc' in executable directory or PATH!\n";
859    return 0;
860  }
861
862  sys::Path RemoteClientPath;
863  if (!RemoteClient.empty())
864    RemoteClientPath = sys::Program::FindProgramByName(RemoteClient);
865
866  Message = "Found gcc: " + GCCPath.str() + "\n";
867  return new GCC(GCCPath, RemoteClientPath, Args);
868}
869