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