brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.5 KiB · c67695f Raw
850 lines · cpp
1//===-- ToolRunner.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the interfaces described in the ToolRunner.h file.10//11//===----------------------------------------------------------------------===//12 13#include "ToolRunner.h"14#include "llvm/Config/config.h"15#include "llvm/Support/CommandLine.h"16#include "llvm/Support/Debug.h"17#include "llvm/Support/FileSystem.h"18#include "llvm/Support/FileUtilities.h"19#include "llvm/Support/Program.h"20#include "llvm/Support/raw_ostream.h"21#include <fstream>22#include <sstream>23#include <utility>24using namespace llvm;25 26#define DEBUG_TYPE "toolrunner"27 28cl::opt<bool> llvm::SaveTemps("save-temps", cl::init(false),29                              cl::desc("Save temporary files"));30 31static cl::opt<std::string>32    RemoteClient("remote-client",33                 cl::desc("Remote execution client (rsh/ssh)"));34 35static cl::opt<std::string>36    RemoteHost("remote-host", cl::desc("Remote execution (rsh/ssh) host"));37 38static cl::opt<std::string>39    RemotePort("remote-port", cl::desc("Remote execution (rsh/ssh) port"));40 41static cl::opt<std::string>42    RemoteUser("remote-user", cl::desc("Remote execution (rsh/ssh) user id"));43 44static cl::opt<std::string>45    RemoteExtra("remote-extra-options",46                cl::desc("Remote execution (rsh/ssh) extra options"));47 48/// RunProgramWithTimeout - This function provides an alternate interface49/// to the sys::Program::ExecuteAndWait interface.50/// @see sys::Program::ExecuteAndWait51static int RunProgramWithTimeout(StringRef ProgramPath,52                                 ArrayRef<StringRef> Args, StringRef StdInFile,53                                 StringRef StdOutFile, StringRef StdErrFile,54                                 unsigned NumSeconds = 0,55                                 unsigned MemoryLimit = 0,56                                 std::string *ErrMsg = nullptr) {57  std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};58  return sys::ExecuteAndWait(ProgramPath, Args, std::nullopt, Redirects,59                             NumSeconds, MemoryLimit, ErrMsg);60}61 62/// RunProgramRemotelyWithTimeout - This function runs the given program63/// remotely using the given remote client and the sys::Program::ExecuteAndWait.64/// Returns the remote program exit code or reports a remote client error if it65/// fails. Remote client is required to return 255 if it failed or program exit66/// code otherwise.67/// @see sys::Program::ExecuteAndWait68static int RunProgramRemotelyWithTimeout(69    StringRef RemoteClientPath, ArrayRef<StringRef> Args, StringRef StdInFile,70    StringRef StdOutFile, StringRef StdErrFile, unsigned NumSeconds = 0,71    unsigned MemoryLimit = 0) {72  std::optional<StringRef> Redirects[3] = {StdInFile, StdOutFile, StdErrFile};73 74  // Run the program remotely with the remote client75  int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, std::nullopt,76                                       Redirects, NumSeconds, MemoryLimit);77 78  // Has the remote client fail?79  if (255 == ReturnCode) {80    std::ostringstream OS;81    OS << "\nError running remote client:\n ";82    for (StringRef Arg : Args)83      OS << " " << Arg.str();84    OS << "\n";85 86    // The error message is in the output file, let's print it out from there.87    std::string StdOutFileName = StdOutFile.str();88    std::ifstream ErrorFile(StdOutFileName.c_str());89    if (ErrorFile) {90      std::copy(std::istreambuf_iterator<char>(ErrorFile),91                std::istreambuf_iterator<char>(),92                std::ostreambuf_iterator<char>(OS));93      ErrorFile.close();94    }95 96    errs() << OS.str();97  }98 99  return ReturnCode;100}101 102static Error ProcessFailure(StringRef ProgPath, ArrayRef<StringRef> Args,103                            unsigned Timeout = 0, unsigned MemoryLimit = 0) {104  std::ostringstream OS;105  OS << "\nError running tool:\n ";106  for (StringRef Arg : Args)107    OS << " " << Arg.str();108  OS << "\n";109 110  // Rerun the compiler, capturing any error messages to print them.111  SmallString<128> ErrorFilename;112  std::error_code EC = sys::fs::createTemporaryFile(113      "bugpoint.program_error_messages", "", ErrorFilename);114  if (EC) {115    errs() << "Error making unique filename: " << EC.message() << "\n";116    exit(1);117  }118 119  RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(),120                        ErrorFilename.str(), Timeout, MemoryLimit);121  // FIXME: check return code ?122 123  // Print out the error messages generated by CC if possible...124  std::ifstream ErrorFile(ErrorFilename.c_str());125  if (ErrorFile) {126    std::copy(std::istreambuf_iterator<char>(ErrorFile),127              std::istreambuf_iterator<char>(),128              std::ostreambuf_iterator<char>(OS));129    ErrorFile.close();130  }131 132  sys::fs::remove(ErrorFilename.c_str());133  return make_error<StringError>(OS.str(), inconvertibleErrorCode());134}135 136//===---------------------------------------------------------------------===//137// LLI Implementation of AbstractIntepreter interface138//139namespace {140class LLI : public AbstractInterpreter {141  std::string LLIPath;               // The path to the LLI executable142  std::vector<std::string> ToolArgs; // Args to pass to LLI143public:144  LLI(const std::string &Path, const std::vector<std::string> *Args)145      : LLIPath(Path) {146    ToolArgs.clear();147    if (Args) {148      ToolArgs = *Args;149    }150  }151 152  Expected<int> ExecuteProgram(153      const std::string &Bitcode, const std::vector<std::string> &Args,154      const std::string &InputFile, const std::string &OutputFile,155      const std::vector<std::string> &CCArgs,156      const std::vector<std::string> &SharedLibs = std::vector<std::string>(),157      unsigned Timeout = 0, unsigned MemoryLimit = 0) override;158};159} // namespace160 161Expected<int> LLI::ExecuteProgram(const std::string &Bitcode,162                                  const std::vector<std::string> &Args,163                                  const std::string &InputFile,164                                  const std::string &OutputFile,165                                  const std::vector<std::string> &CCArgs,166                                  const std::vector<std::string> &SharedLibs,167                                  unsigned Timeout, unsigned MemoryLimit) {168  std::vector<StringRef> LLIArgs;169  LLIArgs.push_back(LLIPath);170  LLIArgs.push_back("-force-interpreter=true");171 172  for (std::vector<std::string>::const_iterator i = SharedLibs.begin(),173                                                e = SharedLibs.end();174       i != e; ++i) {175    LLIArgs.push_back("-load");176    LLIArgs.push_back(*i);177  }178 179  // Add any extra LLI args.180  llvm::append_range(LLIArgs, ToolArgs);181 182  LLIArgs.push_back(Bitcode);183  // Add optional parameters to the running program from Argv184  llvm::append_range(LLIArgs, Args);185 186  outs() << "<lli>";187  outs().flush();188  LLVM_DEBUG(errs() << "\nAbout to run:\t";189             for (unsigned i = 0, e = LLIArgs.size(); i != e; ++i) errs()190             << " " << LLIArgs[i];191             errs() << "\n";);192  return RunProgramWithTimeout(LLIPath, LLIArgs, InputFile, OutputFile,193                               OutputFile, Timeout, MemoryLimit);194}195 196void AbstractInterpreter::anchor() {}197 198ErrorOr<std::string> llvm::FindProgramByName(const std::string &ExeName,199                                             const char *Argv0,200                                             void *MainAddr) {201  // Check the directory that the calling program is in.  We can do202  // this if ProgramPath contains at least one / character, indicating that it203  // is a relative path to the executable itself.204  std::string Main = sys::fs::getMainExecutable(Argv0, MainAddr);205  StringRef Result = sys::path::parent_path(Main);206  if (ErrorOr<std::string> Path = sys::findProgramByName(ExeName, Result))207    return *Path;208 209  // Check the user PATH.210  return sys::findProgramByName(ExeName);211}212 213// LLI create method - Try to find the LLI executable214AbstractInterpreter *215AbstractInterpreter::createLLI(const char *Argv0, std::string &Message,216                               const std::vector<std::string> *ToolArgs) {217  if (ErrorOr<std::string> LLIPath =218      FindProgramByName("lli", Argv0, (void *)(intptr_t)&createLLI)) {219    Message = "Found lli: " + *LLIPath + "\n";220    return new LLI(*LLIPath, ToolArgs);221  } else {222    Message = LLIPath.getError().message() + "\n";223    return nullptr;224  }225}226 227//===---------------------------------------------------------------------===//228// Custom compiler command implementation of AbstractIntepreter interface229//230// Allows using a custom command for compiling the bitcode, thus allows, for231// example, to compile a bitcode fragment without linking or executing, then232// using a custom wrapper script to check for compiler errors.233namespace {234class CustomCompiler : public AbstractInterpreter {235  std::string CompilerCommand;236  std::vector<std::string> CompilerArgs;237 238public:239  CustomCompiler(const std::string &CompilerCmd,240                 std::vector<std::string> CompArgs)241      : CompilerCommand(CompilerCmd), CompilerArgs(std::move(CompArgs)) {}242 243  Error compileProgram(const std::string &Bitcode, unsigned Timeout = 0,244                       unsigned MemoryLimit = 0) override;245 246  Expected<int> ExecuteProgram(247      const std::string &Bitcode, const std::vector<std::string> &Args,248      const std::string &InputFile, const std::string &OutputFile,249      const std::vector<std::string> &CCArgs = std::vector<std::string>(),250      const std::vector<std::string> &SharedLibs = std::vector<std::string>(),251      unsigned Timeout = 0, unsigned MemoryLimit = 0) override {252    return make_error<StringError>(253        "Execution not supported with -compile-custom",254        inconvertibleErrorCode());255  }256};257} // namespace258 259Error CustomCompiler::compileProgram(const std::string &Bitcode,260                                     unsigned Timeout, unsigned MemoryLimit) {261 262  std::vector<StringRef> ProgramArgs;263  ProgramArgs.push_back(CompilerCommand);264 265  llvm::append_range(ProgramArgs, CompilerArgs);266  ProgramArgs.push_back(Bitcode);267 268  // Add optional parameters to the running program from Argv269  llvm::append_range(ProgramArgs, CompilerArgs);270 271  if (RunProgramWithTimeout(CompilerCommand, ProgramArgs, "", "", "", Timeout,272                            MemoryLimit))273    return ProcessFailure(CompilerCommand, ProgramArgs, Timeout, MemoryLimit);274  return Error::success();275}276 277//===---------------------------------------------------------------------===//278// Custom execution command implementation of AbstractIntepreter interface279//280// Allows using a custom command for executing the bitcode, thus allows,281// for example, to invoke a cross compiler for code generation followed by282// a simulator that executes the generated binary.283namespace {284class CustomExecutor : public AbstractInterpreter {285  std::string ExecutionCommand;286  std::vector<std::string> ExecutorArgs;287 288public:289  CustomExecutor(const std::string &ExecutionCmd,290                 std::vector<std::string> ExecArgs)291      : ExecutionCommand(ExecutionCmd), ExecutorArgs(std::move(ExecArgs)) {}292 293  Expected<int> ExecuteProgram(294      const std::string &Bitcode, const std::vector<std::string> &Args,295      const std::string &InputFile, const std::string &OutputFile,296      const std::vector<std::string> &CCArgs,297      const std::vector<std::string> &SharedLibs = std::vector<std::string>(),298      unsigned Timeout = 0, unsigned MemoryLimit = 0) override;299};300} // namespace301 302Expected<int> CustomExecutor::ExecuteProgram(303    const std::string &Bitcode, const std::vector<std::string> &Args,304    const std::string &InputFile, const std::string &OutputFile,305    const std::vector<std::string> &CCArgs,306    const std::vector<std::string> &SharedLibs, unsigned Timeout,307    unsigned MemoryLimit) {308 309  std::vector<StringRef> ProgramArgs;310  ProgramArgs.push_back(ExecutionCommand);311 312  llvm::append_range(ProgramArgs, ExecutorArgs);313  ProgramArgs.push_back(Bitcode);314 315  // Add optional parameters to the running program from Argv316  llvm::append_range(ProgramArgs, Args);317 318  return RunProgramWithTimeout(ExecutionCommand, ProgramArgs, InputFile,319                               OutputFile, OutputFile, Timeout, MemoryLimit);320}321 322// Tokenize the CommandLine to the command and the args to allow323// defining a full command line as the command instead of just the324// executed program. We cannot just pass the whole string after the command325// as a single argument because then the program sees only a single326// command line argument (with spaces in it: "foo bar" instead327// of "foo" and "bar").328//329// Spaces are used as a delimiter; however repeated, leading, and trailing330// whitespace are ignored. Simple escaping is allowed via the '\'331// character, as seen below:332//333// Two consecutive '\' evaluate to a single '\'.334// A space after a '\' evaluates to a space that is not interpreted as a335// delimiter.336// Any other instances of the '\' character are removed.337//338// Example:339// '\\' -> '\'340// '\ ' -> ' '341// 'exa\mple' -> 'example'342//343static void lexCommand(const char *Argv0, std::string &Message,344                       const std::string &CommandLine, std::string &CmdPath,345                       std::vector<std::string> &Args) {346 347  std::string Token;348  std::string Command;349  bool FoundPath = false;350 351  // first argument is the PATH.352  // Skip repeated whitespace, leading whitespace and trailing whitespace.353  for (std::size_t Pos = 0u; Pos <= CommandLine.size(); ++Pos) {354    if ('\\' == CommandLine[Pos]) {355      if (Pos + 1 < CommandLine.size())356        Token.push_back(CommandLine[++Pos]);357 358      continue;359    }360    if (' ' == CommandLine[Pos] || CommandLine.size() == Pos) {361      if (Token.empty())362        continue;363 364      if (!FoundPath) {365        Command = Token;366        FoundPath = true;367        Token.clear();368        continue;369      }370 371      Args.push_back(Token);372      Token.clear();373      continue;374    }375    Token.push_back(CommandLine[Pos]);376  }377 378  auto Path = FindProgramByName(Command, Argv0, (void *)(intptr_t)&lexCommand);379  if (!Path) {380    Message = std::string("Cannot find '") + Command +381              "' in PATH: " + Path.getError().message() + "\n";382    return;383  }384  CmdPath = *Path;385 386  Message = "Found command in: " + CmdPath + "\n";387}388 389// Custom execution environment create method, takes the execution command390// as arguments391AbstractInterpreter *AbstractInterpreter::createCustomCompiler(392    const char *Argv0, std::string &Message,393    const std::string &CompileCommandLine) {394 395  std::string CmdPath;396  std::vector<std::string> Args;397  lexCommand(Argv0, Message, CompileCommandLine, CmdPath, Args);398  if (CmdPath.empty())399    return nullptr;400 401  return new CustomCompiler(CmdPath, Args);402}403 404// Custom execution environment create method, takes the execution command405// as arguments406AbstractInterpreter *407AbstractInterpreter::createCustomExecutor(const char *Argv0,408                                          std::string &Message,409                                          const std::string &ExecCommandLine) {410 411  std::string CmdPath;412  std::vector<std::string> Args;413  lexCommand(Argv0, Message, ExecCommandLine, CmdPath, Args);414  if (CmdPath.empty())415    return nullptr;416 417  return new CustomExecutor(CmdPath, Args);418}419 420//===----------------------------------------------------------------------===//421// LLC Implementation of AbstractIntepreter interface422//423Expected<CC::FileType> LLC::OutputCode(const std::string &Bitcode,424                                       std::string &OutputAsmFile,425                                       unsigned Timeout, unsigned MemoryLimit) {426  const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s");427 428  SmallString<128> UniqueFile;429  std::error_code EC =430      sys::fs::createUniqueFile(Bitcode + "-%%%%%%%" + Suffix, UniqueFile);431  if (EC) {432    errs() << "Error making unique filename: " << EC.message() << "\n";433    exit(1);434  }435  OutputAsmFile = std::string(UniqueFile);436  std::vector<StringRef> LLCArgs;437  LLCArgs.push_back(LLCPath);438 439  // Add any extra LLC args.440  llvm::append_range(LLCArgs, ToolArgs);441 442  LLCArgs.push_back("-o");443  LLCArgs.push_back(OutputAsmFile); // Output to the Asm file444  LLCArgs.push_back(Bitcode);       // This is the input bitcode445 446  if (UseIntegratedAssembler)447    LLCArgs.push_back("-filetype=obj");448 449  outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>");450  outs().flush();451  LLVM_DEBUG(errs() << "\nAbout to run:\t";452             for (unsigned i = 0, e = LLCArgs.size(); i != e; ++i) errs()453             << " " << LLCArgs[i];454             errs() << "\n";);455  if (RunProgramWithTimeout(LLCPath, LLCArgs, "", "", "", Timeout, MemoryLimit))456    return ProcessFailure(LLCPath, LLCArgs, Timeout, MemoryLimit);457  return UseIntegratedAssembler ? CC::ObjectFile : CC::AsmFile;458}459 460Error LLC::compileProgram(const std::string &Bitcode, unsigned Timeout,461                          unsigned MemoryLimit) {462  std::string OutputAsmFile;463  Expected<CC::FileType> Result =464      OutputCode(Bitcode, OutputAsmFile, Timeout, MemoryLimit);465  sys::fs::remove(OutputAsmFile);466  if (Error E = Result.takeError())467    return E;468  return Error::success();469}470 471Expected<int> LLC::ExecuteProgram(const std::string &Bitcode,472                                  const std::vector<std::string> &Args,473                                  const std::string &InputFile,474                                  const std::string &OutputFile,475                                  const std::vector<std::string> &ArgsForCC,476                                  const std::vector<std::string> &SharedLibs,477                                  unsigned Timeout, unsigned MemoryLimit) {478 479  std::string OutputAsmFile;480  Expected<CC::FileType> FileKind =481      OutputCode(Bitcode, OutputAsmFile, Timeout, MemoryLimit);482  FileRemover OutFileRemover(OutputAsmFile, !SaveTemps);483  if (Error E = FileKind.takeError())484    return std::move(E);485 486  std::vector<std::string> CCArgs(ArgsForCC);487  llvm::append_range(CCArgs, SharedLibs);488 489  // Assuming LLC worked, compile the result with CC and run it.490  return cc->ExecuteProgram(OutputAsmFile, Args, *FileKind, InputFile,491                            OutputFile, CCArgs, Timeout, MemoryLimit);492}493 494/// createLLC - Try to find the LLC executable495///496LLC *AbstractInterpreter::createLLC(const char *Argv0, std::string &Message,497                                    const std::string &CCBinary,498                                    const std::vector<std::string> *Args,499                                    const std::vector<std::string> *CCArgs,500                                    bool UseIntegratedAssembler) {501  ErrorOr<std::string> LLCPath =502      FindProgramByName("llc", Argv0, (void *)(intptr_t)&createLLC);503  if (!LLCPath) {504    Message = LLCPath.getError().message() + "\n";505    return nullptr;506  }507 508  CC *cc = CC::create(Argv0, Message, CCBinary, CCArgs);509  if (!cc) {510    errs() << Message << "\n";511    exit(1);512  }513  Message = "Found llc: " + *LLCPath + "\n";514  return new LLC(*LLCPath, cc, Args, UseIntegratedAssembler);515}516 517//===---------------------------------------------------------------------===//518// JIT Implementation of AbstractIntepreter interface519//520namespace {521class JIT : public AbstractInterpreter {522  std::string LLIPath;               // The path to the LLI executable523  std::vector<std::string> ToolArgs; // Args to pass to LLI524public:525  JIT(const std::string &Path, const std::vector<std::string> *Args)526      : LLIPath(Path) {527    ToolArgs.clear();528    if (Args) {529      ToolArgs = *Args;530    }531  }532 533  Expected<int> ExecuteProgram(534      const std::string &Bitcode, const std::vector<std::string> &Args,535      const std::string &InputFile, const std::string &OutputFile,536      const std::vector<std::string> &CCArgs = std::vector<std::string>(),537      const std::vector<std::string> &SharedLibs = std::vector<std::string>(),538      unsigned Timeout = 0, unsigned MemoryLimit = 0) override;539};540} // namespace541 542Expected<int> JIT::ExecuteProgram(const std::string &Bitcode,543                                  const std::vector<std::string> &Args,544                                  const std::string &InputFile,545                                  const std::string &OutputFile,546                                  const std::vector<std::string> &CCArgs,547                                  const std::vector<std::string> &SharedLibs,548                                  unsigned Timeout, unsigned MemoryLimit) {549  // Construct a vector of parameters, incorporating those from the command-line550  std::vector<StringRef> JITArgs;551  JITArgs.push_back(LLIPath);552  JITArgs.push_back("-force-interpreter=false");553 554  // Add any extra LLI args.555  llvm::append_range(JITArgs, ToolArgs);556 557  for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {558    JITArgs.push_back("-load");559    JITArgs.push_back(SharedLibs[i]);560  }561  JITArgs.push_back(Bitcode);562  // Add optional parameters to the running program from Argv563  llvm::append_range(JITArgs, Args);564 565  outs() << "<jit>";566  outs().flush();567  LLVM_DEBUG(errs() << "\nAbout to run:\t";568             for (unsigned i = 0, e = JITArgs.size(); i != e; ++i) errs()569             << " " << JITArgs[i];570             errs() << "\n";);571  LLVM_DEBUG(errs() << "\nSending output to " << OutputFile << "\n");572  return RunProgramWithTimeout(LLIPath, JITArgs, InputFile, OutputFile,573                               OutputFile, Timeout, MemoryLimit);574}575 576/// createJIT - Try to find the LLI executable577///578AbstractInterpreter *579AbstractInterpreter::createJIT(const char *Argv0, std::string &Message,580                               const std::vector<std::string> *Args) {581  if (ErrorOr<std::string> LLIPath =582          FindProgramByName("lli", Argv0, (void *)(intptr_t)&createJIT)) {583    Message = "Found lli: " + *LLIPath + "\n";584    return new JIT(*LLIPath, Args);585  } else {586    Message = LLIPath.getError().message() + "\n";587    return nullptr;588  }589}590 591//===---------------------------------------------------------------------===//592// CC abstraction593//594 595static bool IsARMArchitecture(std::vector<StringRef> Args) {596  for (size_t I = 0; I < Args.size(); ++I) {597    if (!Args[I].equals_insensitive("-arch"))598      continue;599    ++I;600    if (I == Args.size())601      break;602    if (Args[I].starts_with_insensitive("arm"))603      return true;604  }605 606  return false;607}608 609Expected<int> CC::ExecuteProgram(const std::string &ProgramFile,610                                 const std::vector<std::string> &Args,611                                 FileType fileType,612                                 const std::string &InputFile,613                                 const std::string &OutputFile,614                                 const std::vector<std::string> &ArgsForCC,615                                 unsigned Timeout, unsigned MemoryLimit) {616  std::vector<StringRef> CCArgs;617 618  CCArgs.push_back(CCPath);619 620  if (TargetTriple.getArch() == Triple::x86)621    CCArgs.push_back("-m32");622 623  for (std::vector<std::string>::const_iterator I = ccArgs.begin(),624                                                E = ccArgs.end();625       I != E; ++I)626    CCArgs.push_back(*I);627 628  // Specify -x explicitly in case the extension is wonky629  if (fileType != ObjectFile) {630    CCArgs.push_back("-x");631    if (fileType == CFile) {632      CCArgs.push_back("c");633      CCArgs.push_back("-fno-strict-aliasing");634    } else {635      CCArgs.push_back("assembler");636 637      // For ARM architectures we don't want this flag. bugpoint isn't638      // explicitly told what architecture it is working on, so we get639      // it from cc flags640      if (TargetTriple.isOSDarwin() && !IsARMArchitecture(CCArgs))641        CCArgs.push_back("-force_cpusubtype_ALL");642    }643  }644 645  CCArgs.push_back(ProgramFile); // Specify the input filename.646 647  CCArgs.push_back("-x");648  CCArgs.push_back("none");649  CCArgs.push_back("-o");650 651  SmallString<128> OutputBinary;652  std::error_code EC =653      sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.cc.exe", OutputBinary);654  if (EC) {655    errs() << "Error making unique filename: " << EC.message() << "\n";656    exit(1);657  }658  CCArgs.push_back(OutputBinary); // Output to the right file...659 660  // Add any arguments intended for CC. We locate them here because this is661  // most likely -L and -l options that need to come before other libraries but662  // after the source. Other options won't be sensitive to placement on the663  // command line, so this should be safe.664  llvm::append_range(CCArgs, ArgsForCC);665 666  CCArgs.push_back("-lm"); // Hard-code the math library...667  CCArgs.push_back("-O2"); // Optimize the program a bit...668  if (TargetTriple.getArch() == Triple::sparc)669    CCArgs.push_back("-mcpu=v9");670 671  outs() << "<CC>";672  outs().flush();673  LLVM_DEBUG(errs() << "\nAbout to run:\t";674             for (unsigned i = 0, e = CCArgs.size(); i != e; ++i) errs()675             << " " << CCArgs[i];676             errs() << "\n";);677  if (RunProgramWithTimeout(CCPath, CCArgs, "", "", ""))678    return ProcessFailure(CCPath, CCArgs);679 680  std::vector<StringRef> ProgramArgs;681 682  // Declared here so that the destructor only runs after683  // ProgramArgs is used.684  std::string Exec;685 686  if (RemoteClientPath.empty())687    ProgramArgs.push_back(OutputBinary);688  else {689    ProgramArgs.push_back(RemoteClientPath);690    ProgramArgs.push_back(RemoteHost);691    if (!RemoteUser.empty()) {692      ProgramArgs.push_back("-l");693      ProgramArgs.push_back(RemoteUser);694    }695    if (!RemotePort.empty()) {696      ProgramArgs.push_back("-p");697      ProgramArgs.push_back(RemotePort);698    }699    if (!RemoteExtra.empty()) {700      ProgramArgs.push_back(RemoteExtra);701    }702 703    // Full path to the binary. We need to cd to the exec directory because704    // there is a dylib there that the exec expects to find in the CWD705    char *env_pwd = getenv("PWD");706    Exec = "cd ";707    Exec += env_pwd;708    Exec += "; ./";709    Exec += OutputBinary.c_str();710    ProgramArgs.push_back(Exec);711  }712 713  // Add optional parameters to the running program from Argv714  llvm::append_range(ProgramArgs, Args);715 716  // Now that we have a binary, run it!717  outs() << "<program>";718  outs().flush();719  LLVM_DEBUG(720      errs() << "\nAbout to run:\t";721      for (unsigned i = 0, e = ProgramArgs.size(); i != e; ++i) errs()722      << " " << ProgramArgs[i];723      errs() << "\n";);724 725  FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps);726 727  if (RemoteClientPath.empty()) {728    LLVM_DEBUG(errs() << "<run locally>");729    std::string Error;730    int ExitCode = RunProgramWithTimeout(OutputBinary.str(), ProgramArgs,731                                         InputFile, OutputFile, OutputFile,732                                         Timeout, MemoryLimit, &Error);733    // Treat a signal (usually SIGSEGV) or timeout as part of the program output734    // so that crash-causing miscompilation is handled seamlessly.735    if (ExitCode < -1) {736      std::ofstream outFile(OutputFile.c_str(), std::ios_base::app);737      outFile << Error << '\n';738      outFile.close();739    }740    return ExitCode;741  } else {742    outs() << "<run remotely>";743    outs().flush();744    return RunProgramRemotelyWithTimeout(RemoteClientPath, ProgramArgs,745                                         InputFile, OutputFile, OutputFile,746                                         Timeout, MemoryLimit);747  }748}749 750Error CC::MakeSharedObject(const std::string &InputFile, FileType fileType,751                           std::string &OutputFile,752                           const std::vector<std::string> &ArgsForCC) {753  SmallString<128> UniqueFilename;754  std::error_code EC = sys::fs::createUniqueFile(755      InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename);756  if (EC) {757    errs() << "Error making unique filename: " << EC.message() << "\n";758    exit(1);759  }760  OutputFile = std::string(UniqueFilename);761 762  std::vector<StringRef> CCArgs;763 764  CCArgs.push_back(CCPath);765 766  if (TargetTriple.getArch() == Triple::x86)767    CCArgs.push_back("-m32");768 769  for (std::vector<std::string>::const_iterator I = ccArgs.begin(),770                                                E = ccArgs.end();771       I != E; ++I)772    CCArgs.push_back(*I);773 774  // Compile the C/asm file into a shared object775  if (fileType != ObjectFile) {776    CCArgs.push_back("-x");777    CCArgs.push_back(fileType == AsmFile ? "assembler" : "c");778  }779  CCArgs.push_back("-fno-strict-aliasing");780  CCArgs.push_back(InputFile); // Specify the input filename.781  CCArgs.push_back("-x");782  CCArgs.push_back("none");783  if (TargetTriple.getArch() == Triple::sparc)784    CCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc785  else if (TargetTriple.isOSDarwin()) {786    // link all source files into a single module in data segment, rather than787    // generating blocks. dynamic_lookup requires that you set788    // MACOSX_DEPLOYMENT_TARGET=10.3 in your env.  FIXME: it would be better for789    // bugpoint to just pass that in the environment of CC.790    CCArgs.push_back("-single_module");791    CCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC792    CCArgs.push_back("-undefined");793    CCArgs.push_back("dynamic_lookup");794  } else795    CCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others796 797  if (TargetTriple.getArch() == Triple::x86_64)798    CCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC799 800  if (TargetTriple.getArch() == Triple::sparc)801    CCArgs.push_back("-mcpu=v9");802 803  CCArgs.push_back("-o");804  CCArgs.push_back(OutputFile);         // Output to the right filename.805  CCArgs.push_back("-O2");              // Optimize the program a bit.806 807  // Add any arguments intended for CC. We locate them here because this is808  // most likely -L and -l options that need to come before other libraries but809  // after the source. Other options won't be sensitive to placement on the810  // command line, so this should be safe.811  llvm::append_range(CCArgs, ArgsForCC);812 813  outs() << "<CC>";814  outs().flush();815  LLVM_DEBUG(errs() << "\nAbout to run:\t";816             for (unsigned i = 0, e = CCArgs.size(); i != e; ++i) errs()817             << " " << CCArgs[i];818             errs() << "\n";);819  if (RunProgramWithTimeout(CCPath, CCArgs, "", "", ""))820    return ProcessFailure(CCPath, CCArgs);821  return Error::success();822}823 824/// create - Try to find the CC executable825///826CC *CC::create(const char *Argv0, std::string &Message,827               const std::string &CCBinary,828               const std::vector<std::string> *Args) {829  auto CCPath = FindProgramByName(CCBinary, Argv0, (void *)(intptr_t)&create);830  if (!CCPath) {831    Message = "Cannot find `" + CCBinary + "' in PATH: " +832              CCPath.getError().message() + "\n";833    return nullptr;834  }835 836  std::string RemoteClientPath;837  if (!RemoteClient.empty()) {838    auto Path = sys::findProgramByName(RemoteClient);839    if (!Path) {840      Message = "Cannot find `" + RemoteClient + "' in PATH: " +841                Path.getError().message() + "\n";842      return nullptr;843    }844    RemoteClientPath = *Path;845  }846 847  Message = "Found CC: " + *CCPath + "\n";848  return new CC(*CCPath, RemoteClientPath, Args);849}850