LLVM API Documentation

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

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/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 }