ToolRunner.cpp revision 1d29a6d6c7a7f6203065c003d3d2d002870e38a1
1//===-- ToolRunner.cpp ----------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 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. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the interfaces described in the ToolRunner.h file. 11// 12//===----------------------------------------------------------------------===// 13 14#define DEBUG_TYPE "toolrunner" 15#include "llvm/Support/ToolRunner.h" 16#include "Config/config.h" // for HAVE_LINK_R 17#include "Support/Debug.h" 18#include "Support/FileUtilities.h" 19#include <iostream> 20#include <fstream> 21#include <sstream> 22using namespace llvm; 23 24ToolExecutionError::~ToolExecutionError() throw() { } 25 26static void ProcessFailure(std::string ProgPath, const char** Args) { 27 std::ostringstream OS; 28 OS << "\nError running tool:\n "; 29 for (const char **Arg = Args; *Arg; ++Arg) 30 OS << " " << *Arg; 31 OS << "\n"; 32 33 // Rerun the compiler, capturing any error messages to print them. 34 std::string ErrorFilename = getUniqueFilename("error_messages"); 35 RunProgramWithTimeout(ProgPath, Args, "/dev/null", ErrorFilename.c_str(), 36 ErrorFilename.c_str()); 37 38 // Print out the error messages generated by GCC if possible... 39 std::ifstream ErrorFile(ErrorFilename.c_str()); 40 if (ErrorFile) { 41 std::copy(std::istreambuf_iterator<char>(ErrorFile), 42 std::istreambuf_iterator<char>(), 43 std::ostreambuf_iterator<char>(OS)); 44 ErrorFile.close(); 45 } 46 47 removeFile(ErrorFilename); 48 throw ToolExecutionError(OS.str()); 49} 50 51//===---------------------------------------------------------------------===// 52// LLI Implementation of AbstractIntepreter interface 53// 54namespace { 55 class LLI : public AbstractInterpreter { 56 std::string LLIPath; // The path to the LLI executable 57 public: 58 LLI(const std::string &Path) : LLIPath(Path) { } 59 60 61 virtual int ExecuteProgram(const std::string &Bytecode, 62 const std::vector<std::string> &Args, 63 const std::string &InputFile, 64 const std::string &OutputFile, 65 const std::vector<std::string> &SharedLibs = 66 std::vector<std::string>()); 67 }; 68} 69 70int LLI::ExecuteProgram(const std::string &Bytecode, 71 const std::vector<std::string> &Args, 72 const std::string &InputFile, 73 const std::string &OutputFile, 74 const std::vector<std::string> &SharedLibs) { 75 if (!SharedLibs.empty()) 76 throw ToolExecutionError("LLI currently does not support " 77 "loading shared libraries."); 78 79 std::vector<const char*> LLIArgs; 80 LLIArgs.push_back(LLIPath.c_str()); 81 LLIArgs.push_back("-quiet"); 82 LLIArgs.push_back("-force-interpreter=true"); 83 LLIArgs.push_back(Bytecode.c_str()); 84 // Add optional parameters to the running program from Argv 85 for (unsigned i=0, e = Args.size(); i != e; ++i) 86 LLIArgs.push_back(Args[i].c_str()); 87 LLIArgs.push_back(0); 88 89 std::cout << "<lli>" << std::flush; 90 DEBUG(std::cerr << "\nAbout to run:\t"; 91 for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i) 92 std::cerr << " " << LLIArgs[i]; 93 std::cerr << "\n"; 94 ); 95 return RunProgramWithTimeout(LLIPath, &LLIArgs[0], 96 InputFile, OutputFile, OutputFile); 97} 98 99// LLI create method - Try to find the LLI executable 100AbstractInterpreter *AbstractInterpreter::createLLI(const std::string &ProgPath, 101 std::string &Message) { 102 std::string LLIPath = FindExecutable("lli", ProgPath); 103 if (!LLIPath.empty()) { 104 Message = "Found lli: " + LLIPath + "\n"; 105 return new LLI(LLIPath); 106 } 107 108 Message = "Cannot find `lli' in executable directory or PATH!\n"; 109 return 0; 110} 111 112//===----------------------------------------------------------------------===// 113// LLC Implementation of AbstractIntepreter interface 114// 115void LLC::OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile) { 116 OutputAsmFile = getUniqueFilename(Bytecode+".llc.s"); 117 const char *LLCArgs[] = { 118 LLCPath.c_str(), 119 "-o", OutputAsmFile.c_str(), // Output to the Asm file 120 "-f", // Overwrite as necessary... 121 Bytecode.c_str(), // This is the input bytecode 122 0 123 }; 124 125 std::cout << "<llc>" << std::flush; 126 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null", 127 "/dev/null")) 128 ProcessFailure(LLCPath, LLCArgs); 129} 130 131void LLC::compileProgram(const std::string &Bytecode) { 132 std::string OutputAsmFile; 133 OutputAsm(Bytecode, OutputAsmFile); 134 removeFile(OutputAsmFile); 135} 136 137int LLC::ExecuteProgram(const std::string &Bytecode, 138 const std::vector<std::string> &Args, 139 const std::string &InputFile, 140 const std::string &OutputFile, 141 const std::vector<std::string> &SharedLibs) { 142 143 std::string OutputAsmFile; 144 OutputAsm(Bytecode, OutputAsmFile); 145 FileRemover OutFileRemover(OutputAsmFile); 146 147 // Assuming LLC worked, compile the result with GCC and run it. 148 return gcc->ExecuteProgram(OutputAsmFile, Args, GCC::AsmFile, 149 InputFile, OutputFile, SharedLibs); 150} 151 152/// createLLC - Try to find the LLC executable 153/// 154LLC *AbstractInterpreter::createLLC(const std::string &ProgramPath, 155 std::string &Message) { 156 std::string LLCPath = FindExecutable("llc", ProgramPath); 157 if (LLCPath.empty()) { 158 Message = "Cannot find `llc' in executable directory or PATH!\n"; 159 return 0; 160 } 161 162 Message = "Found llc: " + LLCPath + "\n"; 163 GCC *gcc = GCC::create(ProgramPath, Message); 164 if (!gcc) { 165 std::cerr << Message << "\n"; 166 exit(1); 167 } 168 return new LLC(LLCPath, gcc); 169} 170 171//===---------------------------------------------------------------------===// 172// JIT Implementation of AbstractIntepreter interface 173// 174namespace { 175 class JIT : public AbstractInterpreter { 176 std::string LLIPath; // The path to the LLI executable 177 public: 178 JIT(const std::string &Path) : LLIPath(Path) { } 179 180 181 virtual int ExecuteProgram(const std::string &Bytecode, 182 const std::vector<std::string> &Args, 183 const std::string &InputFile, 184 const std::string &OutputFile, 185 const std::vector<std::string> &SharedLibs = 186 std::vector<std::string>()); 187 }; 188} 189 190int JIT::ExecuteProgram(const std::string &Bytecode, 191 const std::vector<std::string> &Args, 192 const std::string &InputFile, 193 const std::string &OutputFile, 194 const std::vector<std::string> &SharedLibs) { 195 // Construct a vector of parameters, incorporating those from the command-line 196 std::vector<const char*> JITArgs; 197 JITArgs.push_back(LLIPath.c_str()); 198 JITArgs.push_back("-quiet"); 199 JITArgs.push_back("-force-interpreter=false"); 200 201 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) { 202 JITArgs.push_back("-load"); 203 JITArgs.push_back(SharedLibs[i].c_str()); 204 } 205 JITArgs.push_back(Bytecode.c_str()); 206 // Add optional parameters to the running program from Argv 207 for (unsigned i=0, e = Args.size(); i != e; ++i) 208 JITArgs.push_back(Args[i].c_str()); 209 JITArgs.push_back(0); 210 211 std::cout << "<jit>" << std::flush; 212 DEBUG(std::cerr << "\nAbout to run:\t"; 213 for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i) 214 std::cerr << " " << JITArgs[i]; 215 std::cerr << "\n"; 216 ); 217 DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n"); 218 return RunProgramWithTimeout(LLIPath, &JITArgs[0], 219 InputFile, OutputFile, OutputFile); 220} 221 222/// createJIT - Try to find the LLI executable 223/// 224AbstractInterpreter *AbstractInterpreter::createJIT(const std::string &ProgPath, 225 std::string &Message) { 226 std::string LLIPath = FindExecutable("lli", ProgPath); 227 if (!LLIPath.empty()) { 228 Message = "Found lli: " + LLIPath + "\n"; 229 return new JIT(LLIPath); 230 } 231 232 Message = "Cannot find `lli' in executable directory or PATH!\n"; 233 return 0; 234} 235 236void CBE::OutputC(const std::string &Bytecode, 237 std::string &OutputCFile) { 238 OutputCFile = getUniqueFilename(Bytecode+".cbe.c"); 239 const char *LLCArgs[] = { 240 LLCPath.c_str(), 241 "-o", OutputCFile.c_str(), // Output to the C file 242 "-march=c", // Output to C 243 "-f", // Overwrite as necessary... 244 Bytecode.c_str(), // This is the input bytecode 245 0 246 }; 247 248 std::cout << "<cbe>" << std::flush; 249 if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null", 250 "/dev/null")) 251 ProcessFailure(LLCPath, LLCArgs); 252} 253 254void CBE::compileProgram(const std::string &Bytecode) { 255 std::string OutputCFile; 256 OutputC(Bytecode, OutputCFile); 257 removeFile(OutputCFile); 258} 259 260int CBE::ExecuteProgram(const std::string &Bytecode, 261 const std::vector<std::string> &Args, 262 const std::string &InputFile, 263 const std::string &OutputFile, 264 const std::vector<std::string> &SharedLibs) { 265 std::string OutputCFile; 266 OutputC(Bytecode, OutputCFile); 267 268 FileRemover CFileRemove(OutputCFile); 269 270 return gcc->ExecuteProgram(OutputCFile, Args, GCC::CFile, 271 InputFile, OutputFile, SharedLibs); 272} 273 274/// createCBE - Try to find the 'llc' executable 275/// 276CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath, 277 std::string &Message) { 278 std::string LLCPath = FindExecutable("llc", ProgramPath); 279 if (LLCPath.empty()) { 280 Message = 281 "Cannot find `llc' in executable directory or PATH!\n"; 282 return 0; 283 } 284 285 Message = "Found llc: " + LLCPath + "\n"; 286 GCC *gcc = GCC::create(ProgramPath, Message); 287 if (!gcc) { 288 std::cerr << Message << "\n"; 289 exit(1); 290 } 291 return new CBE(LLCPath, gcc); 292} 293 294//===---------------------------------------------------------------------===// 295// GCC abstraction 296// 297int GCC::ExecuteProgram(const std::string &ProgramFile, 298 const std::vector<std::string> &Args, 299 FileType fileType, 300 const std::string &InputFile, 301 const std::string &OutputFile, 302 const std::vector<std::string> &SharedLibs) { 303 std::vector<const char*> GCCArgs; 304 305 GCCArgs.push_back(GCCPath.c_str()); 306 307 // Specify the shared libraries to link in... 308 for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) 309 GCCArgs.push_back(SharedLibs[i].c_str()); 310 311 // Specify -x explicitly in case the extension is wonky 312 GCCArgs.push_back("-x"); 313 if (fileType == CFile) { 314 GCCArgs.push_back("c"); 315 GCCArgs.push_back("-fno-strict-aliasing"); 316 } else { 317 GCCArgs.push_back("assembler"); 318 } 319 GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename... 320 GCCArgs.push_back("-o"); 321 std::string OutputBinary = getUniqueFilename(ProgramFile+".gcc.exe"); 322 GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file... 323 GCCArgs.push_back("-lm"); // Hard-code the math library... 324 GCCArgs.push_back("-O2"); // Optimize the program a bit... 325#if defined (HAVE_LINK_R) 326 GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files 327#endif 328 GCCArgs.push_back(0); // NULL terminator 329 330 std::cout << "<gcc>" << std::flush; 331 if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null", 332 "/dev/null")) { 333 ProcessFailure(GCCPath, &GCCArgs[0]); 334 exit(1); 335 } 336 337 std::vector<const char*> ProgramArgs; 338 ProgramArgs.push_back(OutputBinary.c_str()); 339 // Add optional parameters to the running program from Argv 340 for (unsigned i=0, e = Args.size(); i != e; ++i) 341 ProgramArgs.push_back(Args[i].c_str()); 342 ProgramArgs.push_back(0); // NULL terminator 343 344 // Now that we have a binary, run it! 345 std::cout << "<program>" << std::flush; 346 DEBUG(std::cerr << "\nAbout to run:\t"; 347 for (unsigned i=0, e = ProgramArgs.size()-1; i != e; ++i) 348 std::cerr << " " << ProgramArgs[i]; 349 std::cerr << "\n"; 350 ); 351 352 FileRemover OutputBinaryRemover(OutputBinary); 353 return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0], 354 InputFile, OutputFile, OutputFile); 355} 356 357int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, 358 std::string &OutputFile) { 359 OutputFile = getUniqueFilename(InputFile+SHLIBEXT); 360 // Compile the C/asm file into a shared object 361 const char* GCCArgs[] = { 362 GCCPath.c_str(), 363 "-x", (fileType == AsmFile) ? "assembler" : "c", 364 "-fno-strict-aliasing", 365 InputFile.c_str(), // Specify the input filename... 366#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) 367 "-G", // Compile a shared library, `-G' for Sparc 368#else 369 "-shared", // `-shared' for Linux/X86, maybe others 370#endif 371 "-o", OutputFile.c_str(), // Output to the right filename... 372 "-O2", // Optimize the program a bit... 373 0 374 }; 375 376 std::cout << "<gcc>" << std::flush; 377 if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null", 378 "/dev/null")) { 379 ProcessFailure(GCCPath, GCCArgs); 380 return 1; 381 } 382 return 0; 383} 384 385/// create - Try to find the `gcc' executable 386/// 387GCC *GCC::create(const std::string &ProgramPath, std::string &Message) { 388 std::string GCCPath = FindExecutable("gcc", ProgramPath); 389 if (GCCPath.empty()) { 390 Message = "Cannot find `gcc' in executable directory or PATH!\n"; 391 return 0; 392 } 393 394 Message = "Found gcc: " + GCCPath + "\n"; 395 return new GCC(GCCPath); 396} 397