LLVM API Documentation

ToolRunner.cpp

Go to the documentation of this file.
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 }