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