LLVM API Documentation
00001 //===-- ToolRunner.cpp ----------------------------------------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by the LLVM research group and is distributed under 00006 // the University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the interfaces described in the ToolRunner.h file. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #define DEBUG_TYPE "toolrunner" 00015 #include "llvm/Support/ToolRunner.h" 00016 #include "llvm/Config/config.h" // for HAVE_LINK_R 00017 #include "llvm/System/Program.h" 00018 #include "llvm/Support/Debug.h" 00019 #include "llvm/Support/FileUtilities.h" 00020 #include <fstream> 00021 #include <sstream> 00022 #include <iostream> 00023 using namespace llvm; 00024 00025 ToolExecutionError::~ToolExecutionError() throw() { } 00026 00027 /// RunProgramWithTimeout - This function provides an alternate interface to the 00028 /// sys::Program::ExecuteAndWait interface. 00029 /// @see sys:Program::ExecuteAndWait 00030 static int RunProgramWithTimeout(const sys::Path &ProgramPath, 00031 const char **Args, 00032 const sys::Path &StdInFile, 00033 const sys::Path &StdOutFile, 00034 const sys::Path &StdErrFile, 00035 unsigned NumSeconds = 0) { 00036 const sys::Path* redirects[3]; 00037 redirects[0] = &StdInFile; 00038 redirects[1] = &StdOutFile; 00039 redirects[2] = &StdErrFile; 00040 00041 return 00042 sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, NumSeconds); 00043 } 00044 00045 00046 00047 static void ProcessFailure(sys::Path ProgPath, const char** Args) { 00048 std::ostringstream OS; 00049 OS << "\nError running tool:\n "; 00050 for (const char **Arg = Args; *Arg; ++Arg) 00051 OS << " " << *Arg; 00052 OS << "\n"; 00053 00054 // Rerun the compiler, capturing any error messages to print them. 00055 sys::Path ErrorFilename("error_messages"); 00056 ErrorFilename.makeUnique(); 00057 RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename, 00058 ErrorFilename); 00059 00060 // Print out the error messages generated by GCC if possible... 00061 std::ifstream ErrorFile(ErrorFilename.c_str()); 00062 if (ErrorFile) { 00063 std::copy(std::istreambuf_iterator<char>(ErrorFile), 00064 std::istreambuf_iterator<char>(), 00065 std::ostreambuf_iterator<char>(OS)); 00066 ErrorFile.close(); 00067 } 00068 00069 ErrorFilename.eraseFromDisk(); 00070 throw ToolExecutionError(OS.str()); 00071 } 00072 00073 //===---------------------------------------------------------------------===// 00074 // LLI Implementation of AbstractIntepreter interface 00075 // 00076 namespace { 00077 class LLI : public AbstractInterpreter { 00078 std::string LLIPath; // The path to the LLI executable 00079 std::vector<std::string> ToolArgs; // Args to pass to LLI 00080 public: 00081 LLI(const std::string &Path, const std::vector<std::string> *Args) 00082 : LLIPath(Path) { 00083 ToolArgs.clear (); 00084 if (Args) { ToolArgs = *Args; } 00085 } 00086 00087 virtual int ExecuteProgram(const std::string &Bytecode, 00088 const std::vector<std::string> &Args, 00089 const std::string &InputFile, 00090 const std::string &OutputFile, 00091 const std::vector<std::string> &SharedLibs = 00092 std::vector<std::string>(), 00093 unsigned Timeout = 0); 00094 }; 00095 } 00096 00097 int LLI::ExecuteProgram(const std::string &Bytecode, 00098 const std::vector<std::string> &Args, 00099 const std::string &InputFile, 00100 const std::string &OutputFile, 00101 const std::vector<std::string> &SharedLibs, 00102 unsigned Timeout) { 00103 if (!SharedLibs.empty()) 00104 throw ToolExecutionError("LLI currently does not support " 00105 "loading shared libraries."); 00106 00107 std::vector<const char*> LLIArgs; 00108 LLIArgs.push_back(LLIPath.c_str()); 00109 LLIArgs.push_back("-force-interpreter=true"); 00110 00111 // Add any extra LLI args. 00112 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 00113 LLIArgs.push_back(ToolArgs[i].c_str()); 00114 00115 LLIArgs.push_back(Bytecode.c_str()); 00116 // Add optional parameters to the running program from Argv 00117 for (unsigned i=0, e = Args.size(); i != e; ++i) 00118 LLIArgs.push_back(Args[i].c_str()); 00119 LLIArgs.push_back(0); 00120 00121 std::cout << "<lli>" << std::flush; 00122 DEBUG(std::cerr << "\nAbout to run:\t"; 00123 for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i) 00124 std::cerr << " " << LLIArgs[i]; 00125 std::cerr << "\n"; 00126 ); 00127 return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0], 00128 sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), 00129 Timeout); 00130 } 00131 00132 // LLI create method - Try to find the LLI executable 00133 AbstractInterpreter *AbstractInterpreter::createLLI(const std::string &ProgPath, 00134 std::string &Message, 00135 const std::vector<std::string> *ToolArgs) { 00136 std::string LLIPath = FindExecutable("lli", ProgPath).toString(); 00137 if (!LLIPath.empty()) { 00138 Message = "Found lli: " + LLIPath + "\n"; 00139 return new LLI(LLIPath, ToolArgs); 00140 } 00141 00142 Message = "Cannot find `lli' in executable directory or PATH!\n"; 00143 return 0; 00144 } 00145 00146 //===----------------------------------------------------------------------===// 00147 // LLC Implementation of AbstractIntepreter interface 00148 // 00149 void LLC::OutputAsm(const std::string &Bytecode, sys::Path &OutputAsmFile) { 00150 sys::Path uniqueFile(Bytecode+".llc.s"); 00151 uniqueFile.makeUnique(); 00152 OutputAsmFile = uniqueFile; 00153 std::vector<const char *> LLCArgs; 00154 LLCArgs.push_back (LLCPath.c_str()); 00155 00156 // Add any extra LLC args. 00157 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 00158 LLCArgs.push_back(ToolArgs[i].c_str()); 00159 00160 LLCArgs.push_back ("-o"); 00161 LLCArgs.push_back (OutputAsmFile.c_str()); // Output to the Asm file 00162 LLCArgs.push_back ("-f"); // Overwrite as necessary... 00163 LLCArgs.push_back (Bytecode.c_str()); // This is the input bytecode 00164 LLCArgs.push_back (0); 00165 00166 std::cout << "<llc>" << std::flush; 00167 DEBUG(std::cerr << "\nAbout to run:\t"; 00168 for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i) 00169 std::cerr << " " << LLCArgs[i]; 00170 std::cerr << "\n"; 00171 ); 00172 if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0], 00173 sys::Path(), sys::Path(), sys::Path())) 00174 ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]); 00175 } 00176 00177 void LLC::compileProgram(const std::string &Bytecode) { 00178 sys::Path OutputAsmFile; 00179 OutputAsm(Bytecode, OutputAsmFile); 00180 OutputAsmFile.eraseFromDisk(); 00181 } 00182 00183 int LLC::ExecuteProgram(const std::string &Bytecode, 00184 const std::vector<std::string> &Args, 00185 const std::string &InputFile, 00186 const std::string &OutputFile, 00187 const std::vector<std::string> &SharedLibs, 00188 unsigned Timeout) { 00189 00190 sys::Path OutputAsmFile; 00191 OutputAsm(Bytecode, OutputAsmFile); 00192 FileRemover OutFileRemover(OutputAsmFile); 00193 00194 // Assuming LLC worked, compile the result with GCC and run it. 00195 return gcc->ExecuteProgram(OutputAsmFile.toString(), Args, GCC::AsmFile, 00196 InputFile, OutputFile, SharedLibs, Timeout); 00197 } 00198 00199 /// createLLC - Try to find the LLC executable 00200 /// 00201 LLC *AbstractInterpreter::createLLC(const std::string &ProgramPath, 00202 std::string &Message, 00203 const std::vector<std::string> *Args) { 00204 std::string LLCPath = FindExecutable("llc", ProgramPath).toString(); 00205 if (LLCPath.empty()) { 00206 Message = "Cannot find `llc' in executable directory or PATH!\n"; 00207 return 0; 00208 } 00209 00210 Message = "Found llc: " + LLCPath + "\n"; 00211 GCC *gcc = GCC::create(ProgramPath, Message); 00212 if (!gcc) { 00213 std::cerr << Message << "\n"; 00214 exit(1); 00215 } 00216 return new LLC(LLCPath, gcc, Args); 00217 } 00218 00219 //===---------------------------------------------------------------------===// 00220 // JIT Implementation of AbstractIntepreter interface 00221 // 00222 namespace { 00223 class JIT : public AbstractInterpreter { 00224 std::string LLIPath; // The path to the LLI executable 00225 std::vector<std::string> ToolArgs; // Args to pass to LLI 00226 public: 00227 JIT(const std::string &Path, const std::vector<std::string> *Args) 00228 : LLIPath(Path) { 00229 ToolArgs.clear (); 00230 if (Args) { ToolArgs = *Args; } 00231 } 00232 00233 virtual int ExecuteProgram(const std::string &Bytecode, 00234 const std::vector<std::string> &Args, 00235 const std::string &InputFile, 00236 const std::string &OutputFile, 00237 const std::vector<std::string> &SharedLibs = 00238 std::vector<std::string>(), unsigned Timeout =0); 00239 }; 00240 } 00241 00242 int JIT::ExecuteProgram(const std::string &Bytecode, 00243 const std::vector<std::string> &Args, 00244 const std::string &InputFile, 00245 const std::string &OutputFile, 00246 const std::vector<std::string> &SharedLibs, 00247 unsigned Timeout) { 00248 // Construct a vector of parameters, incorporating those from the command-line 00249 std::vector<const char*> JITArgs; 00250 JITArgs.push_back(LLIPath.c_str()); 00251 JITArgs.push_back("-force-interpreter=false"); 00252 00253 // Add any extra LLI args. 00254 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 00255 JITArgs.push_back(ToolArgs[i].c_str()); 00256 00257 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) { 00258 JITArgs.push_back("-load"); 00259 JITArgs.push_back(SharedLibs[i].c_str()); 00260 } 00261 JITArgs.push_back(Bytecode.c_str()); 00262 // Add optional parameters to the running program from Argv 00263 for (unsigned i=0, e = Args.size(); i != e; ++i) 00264 JITArgs.push_back(Args[i].c_str()); 00265 JITArgs.push_back(0); 00266 00267 std::cout << "<jit>" << std::flush; 00268 DEBUG(std::cerr << "\nAbout to run:\t"; 00269 for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i) 00270 std::cerr << " " << JITArgs[i]; 00271 std::cerr << "\n"; 00272 ); 00273 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n"); 00274 return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0], 00275 sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), 00276 Timeout); 00277 } 00278 00279 /// createJIT - Try to find the LLI executable 00280 /// 00281 AbstractInterpreter *AbstractInterpreter::createJIT(const std::string &ProgPath, 00282 std::string &Message, const std::vector<std::string> *Args) { 00283 std::string LLIPath = FindExecutable("lli", ProgPath).toString(); 00284 if (!LLIPath.empty()) { 00285 Message = "Found lli: " + LLIPath + "\n"; 00286 return new JIT(LLIPath, Args); 00287 } 00288 00289 Message = "Cannot find `lli' in executable directory or PATH!\n"; 00290 return 0; 00291 } 00292 00293 void CBE::OutputC(const std::string &Bytecode, sys::Path& OutputCFile) { 00294 sys::Path uniqueFile(Bytecode+".cbe.c"); 00295 uniqueFile.makeUnique(); 00296 OutputCFile = uniqueFile; 00297 std::vector<const char *> LLCArgs; 00298 LLCArgs.push_back (LLCPath.c_str()); 00299 00300 // Add any extra LLC args. 00301 for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) 00302 LLCArgs.push_back(ToolArgs[i].c_str()); 00303 00304 LLCArgs.push_back ("-o"); 00305 LLCArgs.push_back (OutputCFile.c_str()); // Output to the C file 00306 LLCArgs.push_back ("-march=c"); // Output C language 00307 LLCArgs.push_back ("-f"); // Overwrite as necessary... 00308 LLCArgs.push_back (Bytecode.c_str()); // This is the input bytecode 00309 LLCArgs.push_back (0); 00310 00311 std::cout << "<cbe>" << std::flush; 00312 DEBUG(std::cerr << "\nAbout to run:\t"; 00313 for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i) 00314 std::cerr << " " << LLCArgs[i]; 00315 std::cerr << "\n"; 00316 ); 00317 if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(), 00318 sys::Path())) 00319 ProcessFailure(LLCPath, &LLCArgs[0]); 00320 } 00321 00322 void CBE::compileProgram(const std::string &Bytecode) { 00323 sys::Path OutputCFile; 00324 OutputC(Bytecode, OutputCFile); 00325 OutputCFile.eraseFromDisk(); 00326 } 00327 00328 int CBE::ExecuteProgram(const std::string &Bytecode, 00329 const std::vector<std::string> &Args, 00330 const std::string &InputFile, 00331 const std::string &OutputFile, 00332 const std::vector<std::string> &SharedLibs, 00333 unsigned Timeout) { 00334 sys::Path OutputCFile; 00335 OutputC(Bytecode, OutputCFile); 00336 00337 FileRemover CFileRemove(OutputCFile); 00338 00339 return gcc->ExecuteProgram(OutputCFile.toString(), Args, GCC::CFile, 00340 InputFile, OutputFile, SharedLibs, Timeout); 00341 } 00342 00343 /// createCBE - Try to find the 'llc' executable 00344 /// 00345 CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath, 00346 std::string &Message, 00347 const std::vector<std::string> *Args) { 00348 sys::Path LLCPath = FindExecutable("llc", ProgramPath); 00349 if (LLCPath.isEmpty()) { 00350 Message = 00351 "Cannot find `llc' in executable directory or PATH!\n"; 00352 return 0; 00353 } 00354 00355 Message = "Found llc: " + LLCPath.toString() + "\n"; 00356 GCC *gcc = GCC::create(ProgramPath, Message); 00357 if (!gcc) { 00358 std::cerr << Message << "\n"; 00359 exit(1); 00360 } 00361 return new CBE(LLCPath, gcc, Args); 00362 } 00363 00364 //===---------------------------------------------------------------------===// 00365 // GCC abstraction 00366 // 00367 int GCC::ExecuteProgram(const std::string &ProgramFile, 00368 const std::vector<std::string> &Args, 00369 FileType fileType, 00370 const std::string &InputFile, 00371 const std::string &OutputFile, 00372 const std::vector<std::string> &SharedLibs, 00373 unsigned Timeout) { 00374 std::vector<const char*> GCCArgs; 00375 00376 GCCArgs.push_back(GCCPath.c_str()); 00377 00378 // Specify the shared libraries to link in... 00379 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) 00380 GCCArgs.push_back(SharedLibs[i].c_str()); 00381 00382 // Specify -x explicitly in case the extension is wonky 00383 GCCArgs.push_back("-x"); 00384 if (fileType == CFile) { 00385 GCCArgs.push_back("c"); 00386 GCCArgs.push_back("-fno-strict-aliasing"); 00387 } else { 00388 GCCArgs.push_back("assembler"); 00389 #ifdef __APPLE__ 00390 GCCArgs.push_back("-force_cpusubtype_ALL"); 00391 #endif 00392 } 00393 GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename... 00394 GCCArgs.push_back("-o"); 00395 sys::Path OutputBinary (ProgramFile+".gcc.exe"); 00396 OutputBinary.makeUnique(); 00397 GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file... 00398 GCCArgs.push_back("-lm"); // Hard-code the math library... 00399 GCCArgs.push_back("-O2"); // Optimize the program a bit... 00400 #if defined (HAVE_LINK_R) 00401 GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files 00402 #endif 00403 #ifdef __sparc__ 00404 GCCArgs.push_back("-mcpu=v9"); 00405 #endif 00406 GCCArgs.push_back(0); // NULL terminator 00407 00408 std::cout << "<gcc>" << std::flush; 00409 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(), 00410 sys::Path())) { 00411 ProcessFailure(GCCPath, &GCCArgs[0]); 00412 exit(1); 00413 } 00414 00415 std::vector<const char*> ProgramArgs; 00416 00417 ProgramArgs.push_back(OutputBinary.c_str()); 00418 // Add optional parameters to the running program from Argv 00419 for (unsigned i=0, e = Args.size(); i != e; ++i) 00420 ProgramArgs.push_back(Args[i].c_str()); 00421 ProgramArgs.push_back(0); // NULL terminator 00422 00423 // Now that we have a binary, run it! 00424 std::cout << "<program>" << std::flush; 00425 DEBUG(std::cerr << "\nAbout to run:\t"; 00426 for (unsigned i=0, e = ProgramArgs.size()-1; i != e; ++i) 00427 std::cerr << " " << ProgramArgs[i]; 00428 std::cerr << "\n"; 00429 ); 00430 00431 FileRemover OutputBinaryRemover(OutputBinary); 00432 return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], 00433 sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile), 00434 Timeout); 00435 } 00436 00437 int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, 00438 std::string &OutputFile) { 00439 sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT); 00440 uniqueFilename.makeUnique(); 00441 OutputFile = uniqueFilename.toString(); 00442 00443 // Compile the C/asm file into a shared object 00444 const char* GCCArgs[] = { 00445 GCCPath.c_str(), 00446 "-x", (fileType == AsmFile) ? "assembler" : "c", 00447 "-fno-strict-aliasing", 00448 InputFile.c_str(), // Specify the input filename... 00449 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9) 00450 "-G", // Compile a shared library, `-G' for Sparc 00451 #elif defined(__APPLE__) 00452 "-single_module", // link all source files into a single module 00453 "-dynamiclib", // `-dynamiclib' for MacOS X/PowerPC 00454 "-undefined", // in data segment, rather than generating 00455 "dynamic_lookup", // blocks. dynamic_lookup requires that you set 00456 // MACOSX_DEPLOYMENT_TARGET=10.3 in your env. 00457 #else 00458 "-shared", // `-shared' for Linux/X86, maybe others 00459 #endif 00460 00461 #if defined(__ia64__) || defined(__alpha__) 00462 "-fPIC", // IA64 requires shared objs to contain PIC 00463 #endif 00464 #ifdef __sparc__ 00465 "-mcpu=v9", 00466 #endif 00467 "-o", OutputFile.c_str(), // Output to the right filename... 00468 "-O2", // Optimize the program a bit... 00469 0 00470 }; 00471 00472 std::cout << "<gcc>" << std::flush; 00473 if (RunProgramWithTimeout(GCCPath, GCCArgs, sys::Path(), sys::Path(), 00474 sys::Path())) { 00475 ProcessFailure(GCCPath, GCCArgs); 00476 return 1; 00477 } 00478 return 0; 00479 } 00480 00481 /// create - Try to find the `gcc' executable 00482 /// 00483 GCC *GCC::create(const std::string &ProgramPath, std::string &Message) { 00484 sys::Path GCCPath = FindExecutable("gcc", ProgramPath); 00485 if (GCCPath.isEmpty()) { 00486 Message = "Cannot find `gcc' in executable directory or PATH!\n"; 00487 return 0; 00488 } 00489 00490 Message = "Found gcc: " + GCCPath.toString() + "\n"; 00491 return new GCC(GCCPath); 00492 }