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 "Support/Debug.h"
17 #include "Support/FileUtilities.h"
23 //===---------------------------------------------------------------------===//
24 // LLI Implementation of AbstractIntepreter interface
26 class LLI : public AbstractInterpreter {
27 std::string LLIPath; // The path to the LLI executable
29 LLI(const std::string &Path) : LLIPath(Path) { }
32 virtual int ExecuteProgram(const std::string &Bytecode,
33 const std::vector<std::string> &Args,
34 const std::string &InputFile,
35 const std::string &OutputFile,
36 const std::vector<std::string> &SharedLibs =
37 std::vector<std::string>());
40 int LLI::ExecuteProgram(const std::string &Bytecode,
41 const std::vector<std::string> &Args,
42 const std::string &InputFile,
43 const std::string &OutputFile,
44 const std::vector<std::string> &SharedLibs) {
45 if (!SharedLibs.empty()) {
46 std::cerr << "LLI currently does not support loading shared libraries.\n"
51 std::vector<const char*> LLIArgs;
52 LLIArgs.push_back(LLIPath.c_str());
53 LLIArgs.push_back("-quiet");
54 LLIArgs.push_back("-force-interpreter=true");
55 LLIArgs.push_back(Bytecode.c_str());
56 // Add optional parameters to the running program from Argv
57 for (unsigned i=0, e = Args.size(); i != e; ++i)
58 LLIArgs.push_back(Args[i].c_str());
61 std::cout << "<lli>" << std::flush;
62 DEBUG(std::cerr << "\nAbout to run:\t";
63 for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i)
64 std::cerr << " " << LLIArgs[i];
67 return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
68 InputFile, OutputFile, OutputFile);
71 // LLI create method - Try to find the LLI executable
72 AbstractInterpreter *AbstractInterpreter::createLLI(const std::string &ProgPath,
73 std::string &Message) {
74 std::string LLIPath = FindExecutable("lli", ProgPath);
75 if (!LLIPath.empty()) {
76 Message = "Found lli: " + LLIPath + "\n";
77 return new LLI(LLIPath);
80 Message = "Cannot find `lli' in executable directory or PATH!\n";
84 //===----------------------------------------------------------------------===//
85 // LLC Implementation of AbstractIntepreter interface
87 int LLC::OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile) {
88 OutputAsmFile = getUniqueFilename(Bytecode+".llc.s");
89 const char *LLCArgs[] = {
91 "-o", OutputAsmFile.c_str(), // Output to the Asm file
92 "-f", // Overwrite as necessary...
93 Bytecode.c_str(), // This is the input bytecode
97 std::cout << "<llc>" << std::flush;
98 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
100 // If LLC failed on the bytecode, print error...
101 std::cerr << "Error: `llc' failed!\n";
102 removeFile(OutputAsmFile);
109 int LLC::ExecuteProgram(const std::string &Bytecode,
110 const std::vector<std::string> &Args,
111 const std::string &InputFile,
112 const std::string &OutputFile,
113 const std::vector<std::string> &SharedLibs) {
115 std::string OutputAsmFile;
116 if (OutputAsm(Bytecode, OutputAsmFile)) {
117 std::cerr << "Could not generate asm code with `llc', exiting.\n";
121 // Assuming LLC worked, compile the result with GCC and run it.
122 int Result = gcc->ExecuteProgram(OutputAsmFile, Args, GCC::AsmFile,
123 InputFile, OutputFile, SharedLibs);
124 removeFile(OutputAsmFile);
128 /// createLLC - Try to find the LLC executable
130 LLC *AbstractInterpreter::createLLC(const std::string &ProgramPath,
131 std::string &Message) {
132 std::string LLCPath = FindExecutable("llc", ProgramPath);
133 if (LLCPath.empty()) {
134 Message = "Cannot find `llc' in executable directory or PATH!\n";
138 Message = "Found llc: " + LLCPath + "\n";
139 GCC *gcc = GCC::create(ProgramPath, Message);
141 std::cerr << Message << "\n";
144 return new LLC(LLCPath, gcc);
147 //===---------------------------------------------------------------------===//
148 // JIT Implementation of AbstractIntepreter interface
150 class JIT : public AbstractInterpreter {
151 std::string LLIPath; // The path to the LLI executable
153 JIT(const std::string &Path) : LLIPath(Path) { }
156 virtual int ExecuteProgram(const std::string &Bytecode,
157 const std::vector<std::string> &Args,
158 const std::string &InputFile,
159 const std::string &OutputFile,
160 const std::vector<std::string> &SharedLibs =
161 std::vector<std::string>());
164 int JIT::ExecuteProgram(const std::string &Bytecode,
165 const std::vector<std::string> &Args,
166 const std::string &InputFile,
167 const std::string &OutputFile,
168 const std::vector<std::string> &SharedLibs) {
169 // Construct a vector of parameters, incorporating those from the command-line
170 std::vector<const char*> JITArgs;
171 JITArgs.push_back(LLIPath.c_str());
172 JITArgs.push_back("-quiet");
173 JITArgs.push_back("-force-interpreter=false");
175 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {
176 JITArgs.push_back("-load");
177 JITArgs.push_back(SharedLibs[i].c_str());
179 JITArgs.push_back(Bytecode.c_str());
180 // Add optional parameters to the running program from Argv
181 for (unsigned i=0, e = Args.size(); i != e; ++i)
182 JITArgs.push_back(Args[i].c_str());
183 JITArgs.push_back(0);
185 std::cout << "<jit>" << std::flush;
186 DEBUG(std::cerr << "\nAbout to run:\t";
187 for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i)
188 std::cerr << " " << JITArgs[i];
191 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
192 return RunProgramWithTimeout(LLIPath, &JITArgs[0],
193 InputFile, OutputFile, OutputFile);
196 /// createJIT - Try to find the LLI executable
198 AbstractInterpreter *AbstractInterpreter::createJIT(const std::string &ProgPath,
199 std::string &Message) {
200 std::string LLIPath = FindExecutable("lli", ProgPath);
201 if (!LLIPath.empty()) {
202 Message = "Found lli: " + LLIPath + "\n";
203 return new JIT(LLIPath);
206 Message = "Cannot find `lli' in executable directory or PATH!\n";
210 int CBE::OutputC(const std::string &Bytecode,
211 std::string &OutputCFile) {
212 OutputCFile = getUniqueFilename(Bytecode+".cbe.c");
213 const char *DisArgs[] = {
215 "-o", OutputCFile.c_str(), // Output to the C file
217 "-f", // Overwrite as necessary...
218 Bytecode.c_str(), // This is the input bytecode
222 std::cout << "<cbe>" << std::flush;
223 if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
225 // If dis failed on the bytecode, print error...
226 std::cerr << "Error: `llvm-dis -c' failed!\n";
233 int CBE::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::string OutputCFile;
239 if (OutputC(Bytecode, OutputCFile)) {
240 std::cerr << "Could not generate C code with `llvm-dis', exiting.\n";
244 int Result = gcc->ExecuteProgram(OutputCFile, Args, GCC::CFile,
245 InputFile, OutputFile, SharedLibs);
246 removeFile(OutputCFile);
251 /// createCBE - Try to find the 'llvm-dis' executable
253 CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath,
254 std::string &Message) {
255 std::string DISPath = FindExecutable("llvm-dis", ProgramPath);
256 if (DISPath.empty()) {
258 "Cannot find `llvm-dis' in executable directory or PATH!\n";
262 Message = "Found llvm-dis: " + DISPath + "\n";
263 GCC *gcc = GCC::create(ProgramPath, Message);
265 std::cerr << Message << "\n";
268 return new CBE(DISPath, gcc);
271 //===---------------------------------------------------------------------===//
274 int GCC::ExecuteProgram(const std::string &ProgramFile,
275 const std::vector<std::string> &Args,
277 const std::string &InputFile,
278 const std::string &OutputFile,
279 const std::vector<std::string> &SharedLibs) {
280 std::vector<const char*> GCCArgs;
282 GCCArgs.push_back(GCCPath.c_str());
284 // Specify the shared libraries to link in...
285 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i)
286 GCCArgs.push_back(SharedLibs[i].c_str());
288 // Specify -x explicitly in case the extension is wonky
289 GCCArgs.push_back("-x");
290 if (fileType == CFile) {
291 GCCArgs.push_back("c");
292 GCCArgs.push_back("-fno-strict-aliasing");
294 GCCArgs.push_back("assembler");
296 GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename...
297 GCCArgs.push_back("-o");
298 std::string OutputBinary = getUniqueFilename(ProgramFile+".gcc.exe");
299 GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
300 GCCArgs.push_back("-lm"); // Hard-code the math library...
301 GCCArgs.push_back("-O2"); // Optimize the program a bit...
302 GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files
303 GCCArgs.push_back(0); // NULL terminator
305 std::cout << "<gcc>" << std::flush;
306 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
308 ProcessFailure(&GCCArgs[0]);
312 std::vector<const char*> ProgramArgs;
313 ProgramArgs.push_back(OutputBinary.c_str());
314 // Add optional parameters to the running program from Argv
315 for (unsigned i=0, e = Args.size(); i != e; ++i)
316 ProgramArgs.push_back(Args[i].c_str());
317 ProgramArgs.push_back(0); // NULL terminator
319 // Now that we have a binary, run it!
320 std::cout << "<program>" << std::flush;
321 DEBUG(std::cerr << "\nAbout to run:\t";
322 for (unsigned i=0, e = ProgramArgs.size()-1; i != e; ++i)
323 std::cerr << " " << ProgramArgs[i];
326 int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
327 InputFile, OutputFile, OutputFile);
328 removeFile(OutputBinary);
329 return ProgramResult;
332 int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
333 std::string &OutputFile) {
334 OutputFile = getUniqueFilename(InputFile+".so");
335 // Compile the C/asm file into a shared object
336 const char* GCCArgs[] = {
338 "-x", (fileType == AsmFile) ? "assembler" : "c",
339 "-fno-strict-aliasing",
340 InputFile.c_str(), // Specify the input filename...
341 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
342 "-G", // Compile a shared library, `-G' for Sparc
344 "-shared", // `-shared' for Linux/X86, maybe others
346 "-o", OutputFile.c_str(), // Output to the right filename...
347 "-O2", // Optimize the program a bit...
351 std::cout << "<gcc>" << std::flush;
352 if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
354 ProcessFailure(GCCArgs);
360 void GCC::ProcessFailure(const char** GCCArgs) {
361 std::cerr << "\n*** Error: invocation of the C compiler failed!\n";
362 for (const char **Arg = GCCArgs; *Arg; ++Arg)
363 std::cerr << " " << *Arg;
366 // Rerun the compiler, capturing any error messages to print them.
367 std::string ErrorFilename = getUniqueFilename("gcc.errors");
368 RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
369 ErrorFilename.c_str());
371 // Print out the error messages generated by GCC if possible...
372 std::ifstream ErrorFile(ErrorFilename.c_str());
374 std::copy(std::istreambuf_iterator<char>(ErrorFile),
375 std::istreambuf_iterator<char>(),
376 std::ostreambuf_iterator<char>(std::cerr));
381 removeFile(ErrorFilename);
384 /// create - Try to find the `gcc' executable
386 GCC *GCC::create(const std::string &ProgramPath, std::string &Message) {
387 std::string GCCPath = FindExecutable("gcc", ProgramPath);
388 if (GCCPath.empty()) {
389 Message = "Cannot find `gcc' in executable directory or PATH!\n";
393 Message = "Found gcc: " + GCCPath + "\n";
394 return new GCC(GCCPath);
397 } // End llvm namespace