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