Changes For Bug 352
[oota-llvm.git] / lib / Support / ToolRunner.cpp
1 //===-- ToolRunner.cpp ----------------------------------------------------===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source 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 "llvm/Support/ToolRunner.h"
16 #include "llvm/Config/config.h"   // for HAVE_LINK_R
17 #include "llvm/Support/Debug.h"
18 #include "llvm/Support/FileUtilities.h"
19 #include <fstream>
20 #include <sstream>
21 using namespace llvm;
22
23 ToolExecutionError::~ToolExecutionError() throw() { }
24
25 static void ProcessFailure(std::string ProgPath, const char** Args) {
26   std::ostringstream OS;
27   OS << "\nError running tool:\n ";
28   for (const char **Arg = Args; *Arg; ++Arg)
29     OS << " " << *Arg;
30   OS << "\n";
31
32   // Rerun the compiler, capturing any error messages to print them.
33   std::string ErrorFilename = getUniqueFilename("error_messages");
34   RunProgramWithTimeout(ProgPath, Args, "/dev/null", ErrorFilename.c_str(),
35                         ErrorFilename.c_str());
36
37   // Print out the error messages generated by GCC if possible...
38   std::ifstream ErrorFile(ErrorFilename.c_str());
39   if (ErrorFile) {
40     std::copy(std::istreambuf_iterator<char>(ErrorFile),
41               std::istreambuf_iterator<char>(),
42               std::ostreambuf_iterator<char>(OS));
43     ErrorFile.close();
44   }
45
46   removeFile(ErrorFilename);
47   throw ToolExecutionError(OS.str());
48 }
49
50 //===---------------------------------------------------------------------===//
51 // LLI Implementation of AbstractIntepreter interface
52 //
53 namespace {
54   class LLI : public AbstractInterpreter {
55     std::string LLIPath;          // The path to the LLI executable
56     std::vector<std::string> ToolArgs; // Args to pass to LLI
57   public:
58     LLI(const std::string &Path, const std::vector<std::string> *Args)
59       : LLIPath(Path) {
60       ToolArgs.clear ();
61       if (Args) { ToolArgs = *Args; }
62     }
63     
64     virtual int ExecuteProgram(const std::string &Bytecode,
65                                const std::vector<std::string> &Args,
66                                const std::string &InputFile,
67                                const std::string &OutputFile,
68                                const std::vector<std::string> &SharedLibs = 
69                                std::vector<std::string>(),
70                                unsigned Timeout = 0);
71   };
72 }
73
74 int LLI::ExecuteProgram(const std::string &Bytecode,
75                         const std::vector<std::string> &Args,
76                         const std::string &InputFile,
77                         const std::string &OutputFile,
78                         const std::vector<std::string> &SharedLibs,
79                         unsigned Timeout) {
80   if (!SharedLibs.empty())
81     throw ToolExecutionError("LLI currently does not support "
82                              "loading shared libraries.");
83
84   std::vector<const char*> LLIArgs;
85   LLIArgs.push_back(LLIPath.c_str());
86   LLIArgs.push_back("-force-interpreter=true");
87
88   // Add any extra LLI args.
89   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
90     LLIArgs.push_back(ToolArgs[i].c_str());
91
92   LLIArgs.push_back(Bytecode.c_str());
93   // Add optional parameters to the running program from Argv
94   for (unsigned i=0, e = Args.size(); i != e; ++i)
95     LLIArgs.push_back(Args[i].c_str());
96   LLIArgs.push_back(0);
97
98   std::cout << "<lli>" << std::flush;
99   DEBUG(std::cerr << "\nAbout to run:\t";
100         for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i)
101           std::cerr << " " << LLIArgs[i];
102         std::cerr << "\n";
103         );
104   return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
105                                InputFile, OutputFile, OutputFile, Timeout);
106 }
107
108 // LLI create method - Try to find the LLI executable
109 AbstractInterpreter *AbstractInterpreter::createLLI(const std::string &ProgPath,
110                                                     std::string &Message,
111                                      const std::vector<std::string> *ToolArgs) {
112   std::string LLIPath = FindExecutable("lli", ProgPath);
113   if (!LLIPath.empty()) {
114     Message = "Found lli: " + LLIPath + "\n";
115     return new LLI(LLIPath, ToolArgs);
116   }
117
118   Message = "Cannot find `lli' in executable directory or PATH!\n";
119   return 0;
120 }
121
122 //===----------------------------------------------------------------------===//
123 // LLC Implementation of AbstractIntepreter interface
124 //
125 void LLC::OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile) {
126   OutputAsmFile = getUniqueFilename(Bytecode+".llc.s");
127   std::vector<const char *> LLCArgs;
128   LLCArgs.push_back (LLCPath.c_str());
129
130   // Add any extra LLC args.
131   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
132     LLCArgs.push_back(ToolArgs[i].c_str());
133
134   LLCArgs.push_back ("-o");
135   LLCArgs.push_back (OutputAsmFile.c_str()); // Output to the Asm file
136   LLCArgs.push_back ("-f");                  // Overwrite as necessary...
137   LLCArgs.push_back (Bytecode.c_str());      // This is the input bytecode
138   LLCArgs.push_back (0);
139
140   std::cout << "<llc>" << std::flush;
141   DEBUG(std::cerr << "\nAbout to run:\t";
142         for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i)
143           std::cerr << " " << LLCArgs[i];
144         std::cerr << "\n";
145         );
146   if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], "/dev/null", "/dev/null",
147                             "/dev/null"))
148     ProcessFailure(LLCPath, &LLCArgs[0]);
149 }
150
151 void LLC::compileProgram(const std::string &Bytecode) {
152   std::string OutputAsmFile;
153   OutputAsm(Bytecode, OutputAsmFile);
154   removeFile(OutputAsmFile);
155 }
156
157 int LLC::ExecuteProgram(const std::string &Bytecode,
158                         const std::vector<std::string> &Args,
159                         const std::string &InputFile,
160                         const std::string &OutputFile,
161                         const std::vector<std::string> &SharedLibs,
162                         unsigned Timeout) {
163
164   std::string OutputAsmFile;
165   OutputAsm(Bytecode, OutputAsmFile);
166   FileRemover OutFileRemover(OutputAsmFile);
167
168   // Assuming LLC worked, compile the result with GCC and run it.
169   return gcc->ExecuteProgram(OutputAsmFile, Args, GCC::AsmFile,
170                              InputFile, OutputFile, SharedLibs, Timeout);
171 }
172
173 /// createLLC - Try to find the LLC executable
174 ///
175 LLC *AbstractInterpreter::createLLC(const std::string &ProgramPath,
176                                     std::string &Message,
177                                     const std::vector<std::string> *Args) {
178   std::string LLCPath = FindExecutable("llc", ProgramPath);
179   if (LLCPath.empty()) {
180     Message = "Cannot find `llc' in executable directory or PATH!\n";
181     return 0;
182   }
183
184   Message = "Found llc: " + LLCPath + "\n";
185   GCC *gcc = GCC::create(ProgramPath, Message);
186   if (!gcc) {
187     std::cerr << Message << "\n";
188     exit(1);
189   }
190   return new LLC(LLCPath, gcc, Args);
191 }
192
193 //===---------------------------------------------------------------------===//
194 // JIT Implementation of AbstractIntepreter interface
195 //
196 namespace {
197   class JIT : public AbstractInterpreter {
198     std::string LLIPath;          // The path to the LLI executable
199     std::vector<std::string> ToolArgs; // Args to pass to LLI
200   public:
201     JIT(const std::string &Path, const std::vector<std::string> *Args)
202       : LLIPath(Path) {
203       ToolArgs.clear ();
204       if (Args) { ToolArgs = *Args; }
205     }
206     
207     virtual int ExecuteProgram(const std::string &Bytecode,
208                                const std::vector<std::string> &Args,
209                                const std::string &InputFile,
210                                const std::string &OutputFile,
211                                const std::vector<std::string> &SharedLibs = 
212                                std::vector<std::string>(), unsigned Timeout =0);
213   };
214 }
215
216 int JIT::ExecuteProgram(const std::string &Bytecode,
217                         const std::vector<std::string> &Args,
218                         const std::string &InputFile,
219                         const std::string &OutputFile,
220                         const std::vector<std::string> &SharedLibs,
221                         unsigned Timeout) {
222   // Construct a vector of parameters, incorporating those from the command-line
223   std::vector<const char*> JITArgs;
224   JITArgs.push_back(LLIPath.c_str());
225   JITArgs.push_back("-force-interpreter=false");
226
227   // Add any extra LLI args.
228   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
229     JITArgs.push_back(ToolArgs[i].c_str());
230
231   for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {
232     JITArgs.push_back("-load");
233     JITArgs.push_back(SharedLibs[i].c_str());
234   }
235   JITArgs.push_back(Bytecode.c_str());
236   // Add optional parameters to the running program from Argv
237   for (unsigned i=0, e = Args.size(); i != e; ++i)
238     JITArgs.push_back(Args[i].c_str());
239   JITArgs.push_back(0);
240
241   std::cout << "<jit>" << std::flush;
242   DEBUG(std::cerr << "\nAbout to run:\t";
243         for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i)
244           std::cerr << " " << JITArgs[i];
245         std::cerr << "\n";
246         );
247   DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
248   return RunProgramWithTimeout(LLIPath, &JITArgs[0],
249                                InputFile, OutputFile, OutputFile, Timeout);
250 }
251
252 /// createJIT - Try to find the LLI executable
253 ///
254 AbstractInterpreter *AbstractInterpreter::createJIT(const std::string &ProgPath,
255                    std::string &Message, const std::vector<std::string> *Args) {
256   std::string LLIPath = FindExecutable("lli", ProgPath);
257   if (!LLIPath.empty()) {
258     Message = "Found lli: " + LLIPath + "\n";
259     return new JIT(LLIPath, Args);
260   }
261
262   Message = "Cannot find `lli' in executable directory or PATH!\n";
263   return 0;
264 }
265
266 void CBE::OutputC(const std::string &Bytecode,
267                  std::string &OutputCFile) {
268   OutputCFile = getUniqueFilename(Bytecode+".cbe.c");
269   std::vector<const char *> LLCArgs;
270   LLCArgs.push_back (LLCPath.c_str());
271
272   // Add any extra LLC args.
273   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
274     LLCArgs.push_back(ToolArgs[i].c_str());
275
276   LLCArgs.push_back ("-o");
277   LLCArgs.push_back (OutputCFile.c_str());   // Output to the C file
278   LLCArgs.push_back ("-march=c");            // Output C language
279   LLCArgs.push_back ("-f");                  // Overwrite as necessary...
280   LLCArgs.push_back (Bytecode.c_str());      // This is the input bytecode
281   LLCArgs.push_back (0);
282
283   std::cout << "<cbe>" << std::flush;
284   DEBUG(std::cerr << "\nAbout to run:\t";
285         for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i)
286           std::cerr << " " << LLCArgs[i];
287         std::cerr << "\n";
288         );
289   if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], "/dev/null", "/dev/null",
290                             "/dev/null"))
291     ProcessFailure(LLCPath, &LLCArgs[0]);
292 }
293
294 void CBE::compileProgram(const std::string &Bytecode) {
295   std::string OutputCFile;
296   OutputC(Bytecode, OutputCFile);
297   removeFile(OutputCFile);
298 }
299
300 int CBE::ExecuteProgram(const std::string &Bytecode,
301                         const std::vector<std::string> &Args,
302                         const std::string &InputFile,
303                         const std::string &OutputFile,
304                         const std::vector<std::string> &SharedLibs,
305                         unsigned Timeout) {
306   std::string OutputCFile;
307   OutputC(Bytecode, OutputCFile);
308
309   FileRemover CFileRemove(OutputCFile);
310
311   return gcc->ExecuteProgram(OutputCFile, Args, GCC::CFile, 
312                              InputFile, OutputFile, SharedLibs, Timeout);
313 }
314
315 /// createCBE - Try to find the 'llc' executable
316 ///
317 CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath,
318                                     std::string &Message,
319                                     const std::vector<std::string> *Args) {
320   std::string LLCPath = FindExecutable("llc", ProgramPath);
321   if (LLCPath.empty()) {
322     Message = 
323       "Cannot find `llc' in executable directory or PATH!\n";
324     return 0;
325   }
326
327   Message = "Found llc: " + LLCPath + "\n";
328   GCC *gcc = GCC::create(ProgramPath, Message);
329   if (!gcc) {
330     std::cerr << Message << "\n";
331     exit(1);
332   }
333   return new CBE(LLCPath, gcc, Args);
334 }
335
336 //===---------------------------------------------------------------------===//
337 // GCC abstraction
338 //
339 int GCC::ExecuteProgram(const std::string &ProgramFile,
340                         const std::vector<std::string> &Args,
341                         FileType fileType,
342                         const std::string &InputFile,
343                         const std::string &OutputFile,
344                         const std::vector<std::string> &SharedLibs,
345                         unsigned Timeout) {
346   std::vector<const char*> GCCArgs;
347
348   GCCArgs.push_back(GCCPath.c_str());
349
350   // Specify the shared libraries to link in...
351   for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i)
352     GCCArgs.push_back(SharedLibs[i].c_str());
353   
354   // Specify -x explicitly in case the extension is wonky
355   GCCArgs.push_back("-x");
356   if (fileType == CFile) {
357     GCCArgs.push_back("c");
358     GCCArgs.push_back("-fno-strict-aliasing");
359   } else {
360     GCCArgs.push_back("assembler");
361   }
362   GCCArgs.push_back(ProgramFile.c_str());  // Specify the input filename...
363   GCCArgs.push_back("-o");
364   std::string OutputBinary = getUniqueFilename(ProgramFile+".gcc.exe");
365   GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
366   GCCArgs.push_back("-lm");                // Hard-code the math library...
367   GCCArgs.push_back("-O2");                // Optimize the program a bit...
368 #if defined (HAVE_LINK_R)
369   GCCArgs.push_back("-Wl,-R.");            // Search this dir for .so files
370 #endif
371   GCCArgs.push_back(0);                    // NULL terminator
372
373   std::cout << "<gcc>" << std::flush;
374   if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
375                             "/dev/null")) {
376     ProcessFailure(GCCPath, &GCCArgs[0]);
377     exit(1);
378   }
379
380   std::vector<const char*> ProgramArgs;
381   ProgramArgs.push_back(OutputBinary.c_str());
382   // Add optional parameters to the running program from Argv
383   for (unsigned i=0, e = Args.size(); i != e; ++i)
384     ProgramArgs.push_back(Args[i].c_str());
385   ProgramArgs.push_back(0);                // NULL terminator
386
387   // Now that we have a binary, run it!
388   std::cout << "<program>" << std::flush;
389   DEBUG(std::cerr << "\nAbout to run:\t";
390         for (unsigned i=0, e = ProgramArgs.size()-1; i != e; ++i)
391           std::cerr << " " << ProgramArgs[i];
392         std::cerr << "\n";
393         );
394
395   FileRemover OutputBinaryRemover(OutputBinary);
396   return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
397                                InputFile, OutputFile, OutputFile, Timeout);
398 }
399
400 int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
401                           std::string &OutputFile) {
402   OutputFile = getUniqueFilename(InputFile+SHLIBEXT);
403   // Compile the C/asm file into a shared object
404   const char* GCCArgs[] = {
405     GCCPath.c_str(),
406     "-x", (fileType == AsmFile) ? "assembler" : "c",
407     "-fno-strict-aliasing",
408     InputFile.c_str(),           // Specify the input filename...
409 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
410     "-G",                        // Compile a shared library, `-G' for Sparc
411 #elif (defined(__POWERPC__) || defined(__ppc__)) && defined(__APPLE__)
412     "-dynamiclib",               // `-dynamiclib' for MacOS X/PowerPC
413     "-fno-common",               // allow global vars w/o initializers to live
414     "-undefined",                // in data segment, rather than generating
415     "dynamic_lookup",            // blocks. dynamic_lookup requires that you set
416                                  // MACOSX_DEPLOYMENT_TARGET=10.3 in your env.
417 #else
418     "-shared",                   // `-shared' for Linux/X86, maybe others
419 #endif
420     "-o", OutputFile.c_str(),    // Output to the right filename...
421     "-O2",                       // Optimize the program a bit...
422     0
423   };
424   
425   std::cout << "<gcc>" << std::flush;
426   if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
427                             "/dev/null")) {
428     ProcessFailure(GCCPath, GCCArgs);
429     return 1;
430   }
431   return 0;
432 }
433
434 /// create - Try to find the `gcc' executable
435 ///
436 GCC *GCC::create(const std::string &ProgramPath, std::string &Message) {
437   std::string GCCPath = FindExecutable("gcc", ProgramPath);
438   if (GCCPath.empty()) {
439     Message = "Cannot find `gcc' in executable directory or PATH!\n";
440     return 0;
441   }
442
443   Message = "Found gcc: " + GCCPath + "\n";
444   return new GCC(GCCPath);
445 }