1 //===-- ToolRunner.cpp ----------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
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.
8 //===----------------------------------------------------------------------===//
10 // This file implements the interfaces described in the ToolRunner.h file.
12 //===----------------------------------------------------------------------===//
14 #define DEBUG_TYPE "toolrunner"
15 #include "llvm/Support/ToolRunner.h"
16 #include "llvm/Config/config.h" // for HAVE_LINK_R
17 #include "llvm/System/Program.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/FileUtilities.h"
25 ToolExecutionError::~ToolExecutionError() throw() { }
27 /// RunProgramWithTimeout - This function provides an alternate interface to the
28 /// sys::Program::ExecuteAndWait interface.
29 /// @see sys:Program::ExecuteAndWait
30 static int RunProgramWithTimeout(const sys::Path &ProgramPath,
32 const sys::Path &StdInFile,
33 const sys::Path &StdOutFile,
34 const sys::Path &StdErrFile,
35 unsigned NumSeconds = 0) {
36 const sys::Path* redirects[3];
37 redirects[0] = &StdInFile;
38 redirects[1] = &StdOutFile;
39 redirects[2] = &StdErrFile;
42 sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, NumSeconds);
47 static void ProcessFailure(sys::Path ProgPath, const char** Args) {
48 std::ostringstream OS;
49 OS << "\nError running tool:\n ";
50 for (const char **Arg = Args; *Arg; ++Arg)
54 // Rerun the compiler, capturing any error messages to print them.
55 sys::Path ErrorFilename("error_messages");
56 ErrorFilename.makeUnique();
57 RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename,
60 // Print out the error messages generated by GCC if possible...
61 std::ifstream ErrorFile(ErrorFilename.c_str());
63 std::copy(std::istreambuf_iterator<char>(ErrorFile),
64 std::istreambuf_iterator<char>(),
65 std::ostreambuf_iterator<char>(OS));
69 ErrorFilename.eraseFromDisk();
70 throw ToolExecutionError(OS.str());
73 //===---------------------------------------------------------------------===//
74 // LLI Implementation of AbstractIntepreter interface
77 class LLI : public AbstractInterpreter {
78 std::string LLIPath; // The path to the LLI executable
79 std::vector<std::string> ToolArgs; // Args to pass to LLI
81 LLI(const std::string &Path, const std::vector<std::string> *Args)
84 if (Args) { ToolArgs = *Args; }
87 virtual int ExecuteProgram(const std::string &Bytecode,
88 const std::vector<std::string> &Args,
89 const std::string &InputFile,
90 const std::string &OutputFile,
91 const std::vector<std::string> &SharedLibs =
92 std::vector<std::string>(),
93 unsigned Timeout = 0);
97 int LLI::ExecuteProgram(const std::string &Bytecode,
98 const std::vector<std::string> &Args,
99 const std::string &InputFile,
100 const std::string &OutputFile,
101 const std::vector<std::string> &SharedLibs,
103 if (!SharedLibs.empty())
104 throw ToolExecutionError("LLI currently does not support "
105 "loading shared libraries.");
107 std::vector<const char*> LLIArgs;
108 LLIArgs.push_back(LLIPath.c_str());
109 LLIArgs.push_back("-force-interpreter=true");
111 // Add any extra LLI args.
112 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
113 LLIArgs.push_back(ToolArgs[i].c_str());
115 LLIArgs.push_back(Bytecode.c_str());
116 // Add optional parameters to the running program from Argv
117 for (unsigned i=0, e = Args.size(); i != e; ++i)
118 LLIArgs.push_back(Args[i].c_str());
119 LLIArgs.push_back(0);
121 std::cout << "<lli>" << std::flush;
122 DEBUG(std::cerr << "\nAbout to run:\t";
123 for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i)
124 std::cerr << " " << LLIArgs[i];
127 return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0],
128 sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
132 // LLI create method - Try to find the LLI executable
133 AbstractInterpreter *AbstractInterpreter::createLLI(const std::string &ProgPath,
134 std::string &Message,
135 const std::vector<std::string> *ToolArgs) {
136 std::string LLIPath = FindExecutable("lli", ProgPath).toString();
137 if (!LLIPath.empty()) {
138 Message = "Found lli: " + LLIPath + "\n";
139 return new LLI(LLIPath, ToolArgs);
142 Message = "Cannot find `lli' in executable directory or PATH!\n";
146 //===----------------------------------------------------------------------===//
147 // LLC Implementation of AbstractIntepreter interface
149 void LLC::OutputAsm(const std::string &Bytecode, sys::Path &OutputAsmFile) {
150 sys::Path uniqueFile(Bytecode+".llc.s");
151 uniqueFile.makeUnique();
152 OutputAsmFile = uniqueFile;
153 std::vector<const char *> LLCArgs;
154 LLCArgs.push_back (LLCPath.c_str());
156 // Add any extra LLC args.
157 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
158 LLCArgs.push_back(ToolArgs[i].c_str());
160 LLCArgs.push_back ("-o");
161 LLCArgs.push_back (OutputAsmFile.c_str()); // Output to the Asm file
162 LLCArgs.push_back ("-f"); // Overwrite as necessary...
163 LLCArgs.push_back (Bytecode.c_str()); // This is the input bytecode
164 LLCArgs.push_back (0);
166 std::cout << "<llc>" << std::flush;
167 DEBUG(std::cerr << "\nAbout to run:\t";
168 for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i)
169 std::cerr << " " << LLCArgs[i];
172 if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0],
173 sys::Path(), sys::Path(), sys::Path()))
174 ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]);
177 void LLC::compileProgram(const std::string &Bytecode) {
178 sys::Path OutputAsmFile;
179 OutputAsm(Bytecode, OutputAsmFile);
180 OutputAsmFile.eraseFromDisk();
183 int LLC::ExecuteProgram(const std::string &Bytecode,
184 const std::vector<std::string> &Args,
185 const std::string &InputFile,
186 const std::string &OutputFile,
187 const std::vector<std::string> &SharedLibs,
190 sys::Path OutputAsmFile;
191 OutputAsm(Bytecode, OutputAsmFile);
192 FileRemover OutFileRemover(OutputAsmFile);
194 // Assuming LLC worked, compile the result with GCC and run it.
195 return gcc->ExecuteProgram(OutputAsmFile.toString(), Args, GCC::AsmFile,
196 InputFile, OutputFile, SharedLibs, Timeout);
199 /// createLLC - Try to find the LLC executable
201 LLC *AbstractInterpreter::createLLC(const std::string &ProgramPath,
202 std::string &Message,
203 const std::vector<std::string> *Args) {
204 std::string LLCPath = FindExecutable("llc", ProgramPath).toString();
205 if (LLCPath.empty()) {
206 Message = "Cannot find `llc' in executable directory or PATH!\n";
210 Message = "Found llc: " + LLCPath + "\n";
211 GCC *gcc = GCC::create(ProgramPath, Message);
213 std::cerr << Message << "\n";
216 return new LLC(LLCPath, gcc, Args);
219 //===---------------------------------------------------------------------===//
220 // JIT Implementation of AbstractIntepreter interface
223 class JIT : public AbstractInterpreter {
224 std::string LLIPath; // The path to the LLI executable
225 std::vector<std::string> ToolArgs; // Args to pass to LLI
227 JIT(const std::string &Path, const std::vector<std::string> *Args)
230 if (Args) { ToolArgs = *Args; }
233 virtual int ExecuteProgram(const std::string &Bytecode,
234 const std::vector<std::string> &Args,
235 const std::string &InputFile,
236 const std::string &OutputFile,
237 const std::vector<std::string> &SharedLibs =
238 std::vector<std::string>(), unsigned Timeout =0);
242 int JIT::ExecuteProgram(const std::string &Bytecode,
243 const std::vector<std::string> &Args,
244 const std::string &InputFile,
245 const std::string &OutputFile,
246 const std::vector<std::string> &SharedLibs,
248 // Construct a vector of parameters, incorporating those from the command-line
249 std::vector<const char*> JITArgs;
250 JITArgs.push_back(LLIPath.c_str());
251 JITArgs.push_back("-force-interpreter=false");
253 // Add any extra LLI args.
254 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
255 JITArgs.push_back(ToolArgs[i].c_str());
257 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {
258 JITArgs.push_back("-load");
259 JITArgs.push_back(SharedLibs[i].c_str());
261 JITArgs.push_back(Bytecode.c_str());
262 // Add optional parameters to the running program from Argv
263 for (unsigned i=0, e = Args.size(); i != e; ++i)
264 JITArgs.push_back(Args[i].c_str());
265 JITArgs.push_back(0);
267 std::cout << "<jit>" << std::flush;
268 DEBUG(std::cerr << "\nAbout to run:\t";
269 for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i)
270 std::cerr << " " << JITArgs[i];
273 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
274 return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0],
275 sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
279 /// createJIT - Try to find the LLI executable
281 AbstractInterpreter *AbstractInterpreter::createJIT(const std::string &ProgPath,
282 std::string &Message, const std::vector<std::string> *Args) {
283 std::string LLIPath = FindExecutable("lli", ProgPath).toString();
284 if (!LLIPath.empty()) {
285 Message = "Found lli: " + LLIPath + "\n";
286 return new JIT(LLIPath, Args);
289 Message = "Cannot find `lli' in executable directory or PATH!\n";
293 void CBE::OutputC(const std::string &Bytecode, sys::Path& OutputCFile) {
294 sys::Path uniqueFile(Bytecode+".cbe.c");
295 uniqueFile.makeUnique();
296 OutputCFile = uniqueFile;
297 std::vector<const char *> LLCArgs;
298 LLCArgs.push_back (LLCPath.c_str());
300 // Add any extra LLC args.
301 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
302 LLCArgs.push_back(ToolArgs[i].c_str());
304 LLCArgs.push_back ("-o");
305 LLCArgs.push_back (OutputCFile.c_str()); // Output to the C file
306 LLCArgs.push_back ("-march=c"); // Output C language
307 LLCArgs.push_back ("-f"); // Overwrite as necessary...
308 LLCArgs.push_back (Bytecode.c_str()); // This is the input bytecode
309 LLCArgs.push_back (0);
311 std::cout << "<cbe>" << std::flush;
312 DEBUG(std::cerr << "\nAbout to run:\t";
313 for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i)
314 std::cerr << " " << LLCArgs[i];
317 if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(),
319 ProcessFailure(LLCPath, &LLCArgs[0]);
322 void CBE::compileProgram(const std::string &Bytecode) {
323 sys::Path OutputCFile;
324 OutputC(Bytecode, OutputCFile);
325 OutputCFile.eraseFromDisk();
328 int CBE::ExecuteProgram(const std::string &Bytecode,
329 const std::vector<std::string> &Args,
330 const std::string &InputFile,
331 const std::string &OutputFile,
332 const std::vector<std::string> &SharedLibs,
334 sys::Path OutputCFile;
335 OutputC(Bytecode, OutputCFile);
337 FileRemover CFileRemove(OutputCFile);
339 return gcc->ExecuteProgram(OutputCFile.toString(), Args, GCC::CFile,
340 InputFile, OutputFile, SharedLibs, Timeout);
343 /// createCBE - Try to find the 'llc' executable
345 CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath,
346 std::string &Message,
347 const std::vector<std::string> *Args) {
348 sys::Path LLCPath = FindExecutable("llc", ProgramPath);
349 if (LLCPath.isEmpty()) {
351 "Cannot find `llc' in executable directory or PATH!\n";
355 Message = "Found llc: " + LLCPath.toString() + "\n";
356 GCC *gcc = GCC::create(ProgramPath, Message);
358 std::cerr << Message << "\n";
361 return new CBE(LLCPath, gcc, Args);
364 //===---------------------------------------------------------------------===//
367 int GCC::ExecuteProgram(const std::string &ProgramFile,
368 const std::vector<std::string> &Args,
370 const std::string &InputFile,
371 const std::string &OutputFile,
372 const std::vector<std::string> &SharedLibs,
374 std::vector<const char*> GCCArgs;
376 GCCArgs.push_back(GCCPath.c_str());
378 // Specify the shared libraries to link in...
379 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i)
380 GCCArgs.push_back(SharedLibs[i].c_str());
382 // Specify -x explicitly in case the extension is wonky
383 GCCArgs.push_back("-x");
384 if (fileType == CFile) {
385 GCCArgs.push_back("c");
386 GCCArgs.push_back("-fno-strict-aliasing");
388 GCCArgs.push_back("assembler");
390 GCCArgs.push_back("-force_cpusubtype_ALL");
393 GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename...
394 GCCArgs.push_back("-o");
395 sys::Path OutputBinary (ProgramFile+".gcc.exe");
396 OutputBinary.makeUnique();
397 GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
398 GCCArgs.push_back("-lm"); // Hard-code the math library...
399 GCCArgs.push_back("-O2"); // Optimize the program a bit...
400 #if defined (HAVE_LINK_R)
401 GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files
404 GCCArgs.push_back("-mcpu=v9");
406 GCCArgs.push_back(0); // NULL terminator
408 std::cout << "<gcc>" << std::flush;
409 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(),
411 ProcessFailure(GCCPath, &GCCArgs[0]);
415 std::vector<const char*> ProgramArgs;
417 ProgramArgs.push_back(OutputBinary.c_str());
418 // Add optional parameters to the running program from Argv
419 for (unsigned i=0, e = Args.size(); i != e; ++i)
420 ProgramArgs.push_back(Args[i].c_str());
421 ProgramArgs.push_back(0); // NULL terminator
423 // Now that we have a binary, run it!
424 std::cout << "<program>" << std::flush;
425 DEBUG(std::cerr << "\nAbout to run:\t";
426 for (unsigned i=0, e = ProgramArgs.size()-1; i != e; ++i)
427 std::cerr << " " << ProgramArgs[i];
431 FileRemover OutputBinaryRemover(OutputBinary);
432 return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
433 sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
437 int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
438 std::string &OutputFile) {
439 sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT);
440 uniqueFilename.makeUnique();
441 OutputFile = uniqueFilename.toString();
443 // Compile the C/asm file into a shared object
444 const char* GCCArgs[] = {
446 "-x", (fileType == AsmFile) ? "assembler" : "c",
447 "-fno-strict-aliasing",
448 InputFile.c_str(), // Specify the input filename...
449 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
450 "-G", // Compile a shared library, `-G' for Sparc
451 #elif defined(__APPLE__)
452 "-single_module", // link all source files into a single module
453 "-dynamiclib", // `-dynamiclib' for MacOS X/PowerPC
454 "-undefined", // in data segment, rather than generating
455 "dynamic_lookup", // blocks. dynamic_lookup requires that you set
456 // MACOSX_DEPLOYMENT_TARGET=10.3 in your env.
458 "-shared", // `-shared' for Linux/X86, maybe others
461 #if defined(__ia64__) || defined(__alpha__)
462 "-fPIC", // IA64 requires shared objs to contain PIC
467 "-o", OutputFile.c_str(), // Output to the right filename...
468 "-O2", // Optimize the program a bit...
472 std::cout << "<gcc>" << std::flush;
473 if (RunProgramWithTimeout(GCCPath, GCCArgs, sys::Path(), sys::Path(),
475 ProcessFailure(GCCPath, GCCArgs);
481 /// create - Try to find the `gcc' executable
483 GCC *GCC::create(const std::string &ProgramPath, std::string &Message) {
484 sys::Path GCCPath = FindExecutable("gcc", ProgramPath);
485 if (GCCPath.isEmpty()) {
486 Message = "Cannot find `gcc' in executable directory or PATH!\n";
490 Message = "Found gcc: " + GCCPath.toString() + "\n";
491 return new GCC(GCCPath);