/// RunProgramRemotelyWithTimeout - This function runs the given program /// remotely using the given remote client and the sys::Program::ExecuteAndWait. /// Returns the remote program exit code or reports a remote client error if it /// fails. Remote client is required to return 255 if it failed or program exit /// code otherwise. /// @see sys::Program::ExecuteAndWait static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, const char **Args, const sys::Path &StdInFile, const sys::Path &StdOutFile, const sys::Path &StdErrFile, unsigned NumSeconds = 0, unsigned MemoryLimit = 0) { const sys::Path* redirects[3]; redirects[0] = &StdInFile; redirects[1] = &StdOutFile; redirects[2] = &StdErrFile; #if 0 // For debug purposes { errs() << "RUN:"; for (unsigned i = 0; Args[i]; ++i) errs() << " " << Args[i]; errs() << "\n"; } #endif // Run the program remotely with the remote client int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args, 0, redirects, NumSeconds, MemoryLimit); // Has the remote client fail? if (255 == ReturnCode) { std::ostringstream OS; OS << "\nError running remote client:\n "; for (const char **Arg = Args; *Arg; ++Arg) OS << " " << *Arg; OS << "\n"; // The error message is in the output file, let's print it out from there. std::ifstream ErrorFile(StdOutFile.c_str()); if (ErrorFile) { std::copy(std::istreambuf_iterator<char>(ErrorFile), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(OS)); ErrorFile.close(); } errs() << OS.str(); } return ReturnCode; }
bool LTOCodeGenerator::assemble(const std::string& asmPath, const std::string& objPath, std::string& errMsg) { // find compiler driver const sys::Path gcc = sys::Program::FindProgramByName("gcc"); if ( gcc.isEmpty() ) { errMsg = "can't locate gcc"; return true; } // build argument list std::vector<const char*> args; std::string targetTriple = _linker.getModule()->getTargetTriple(); args.push_back(gcc.c_str()); if ( targetTriple.find("darwin") != targetTriple.size() ) { if (strncmp(targetTriple.c_str(), "i686-apple-", 11) == 0) { args.push_back("-arch"); args.push_back("i386"); } else if (strncmp(targetTriple.c_str(), "x86_64-apple-", 13) == 0) { args.push_back("-arch"); args.push_back("x86_64"); } else if (strncmp(targetTriple.c_str(), "powerpc-apple-", 14) == 0) { args.push_back("-arch"); args.push_back("ppc"); } else if (strncmp(targetTriple.c_str(), "powerpc64-apple-", 16) == 0) { args.push_back("-arch"); args.push_back("ppc64"); } } args.push_back("-c"); args.push_back("-x"); args.push_back("assembler"); args.push_back("-o"); args.push_back(objPath.c_str()); args.push_back(asmPath.c_str()); args.push_back(0); // invoke assembler if ( sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 0, 0, &errMsg) ) { errMsg = "error in assembly"; return true; } return false; // success }
// LoadObject - Read in and parse the bitcode file named by FN and return the // module it contains (wrapped in an auto_ptr), or auto_ptr<Module>() and set // Error if an error occurs. std::auto_ptr<Module> Linker::LoadObject(const sys::Path &FN) { std::string ParseErrorMessage; Module *Result = 0; OwningPtr<MemoryBuffer> Buffer; if (error_code ec = MemoryBuffer::getFileOrSTDIN(FN.c_str(), Buffer)) ParseErrorMessage = "Error reading file '" + FN.str() + "'" + ": " + ec.message(); else Result = ParseBitcodeFile(Buffer.get(), Context, &ParseErrorMessage); if (Result) return std::auto_ptr<Module>(Result); Error = "Bitcode file '" + FN.str() + "' could not be loaded"; if (ParseErrorMessage.size()) Error += ": " + ParseErrorMessage; return std::auto_ptr<Module>(); }
/// GenerateAssembly - generates a native assembly language source file from the /// specified bytecode file. /// /// Inputs: /// InputFilename - The name of the input bytecode file. /// OutputFilename - The name of the file to generate. /// llc - The pathname to use for LLC. /// envp - The environment to use when running LLC. /// /// Return non-zero value on error. /// static int GenerateAssembly(const std::string &OutputFilename, const std::string &InputFilename, const sys::Path &llc, std::string &ErrMsg ) { // Run LLC to convert the bytecode file into assembly code. std::vector<const char*> args; args.push_back(llc.c_str()); args.push_back("-f"); args.push_back("-o"); args.push_back(OutputFilename.c_str()); args.push_back(InputFilename.c_str()); args.push_back(0); if (Verbose) { cout << "Generating Assembly With: \n"; PrintCommand(args); } return sys::Program::ExecuteAndWait(llc, &args[0], 0, 0, 0, 0, &ErrMsg); }
/// GenerateCFile - generates a C source file from the specified bitcode file. static int GenerateCFile(const std::string &OutputFile, const std::string &InputFile, const sys::Path &llc, std::string& ErrMsg) { // Run LLC to convert the bitcode file into C. std::vector<const char*> args; args.push_back(llc.c_str()); args.push_back("-march=c"); args.push_back("-o"); args.push_back(OutputFile.c_str()); args.push_back(InputFile.c_str()); args.push_back(0); if (Verbose) { errs() << "Generating C Source With: \n"; PrintCommand(args); } return sys::Program::ExecuteAndWait(llc, &args[0], 0, 0, 0, 0, &ErrMsg); }
// Get just the externally visible defined symbols from the bitcode bool llvm::GetBitcodeSymbols(const sys::Path& fName, LLVMContext& Context, std::vector<std::string>& symbols, std::string* ErrMsg) { OwningPtr<MemoryBuffer> Buffer; if (error_code ec = MemoryBuffer::getFileOrSTDIN(fName.c_str(), Buffer)) { if (ErrMsg) *ErrMsg = "Could not open file '" + fName.str() + "'" + ": " + ec.message(); return true; } Module *M = ParseBitcodeFile(Buffer.get(), Context, ErrMsg); if (!M) return true; // Get the symbols getSymbols(M, symbols); // Done with the module. delete M; return true; }
/// GenerateAssembly - generates a native assembly language source file from the /// specified bitcode file. /// /// Inputs: /// InputFilename - The name of the input bitcode file. /// OutputFilename - The name of the file to generate. /// llc - The pathname to use for LLC. /// envp - The environment to use when running LLC. /// /// Return non-zero value on error. /// static int GenerateAssembly(const std::string &OutputFilename, const std::string &InputFilename, const sys::Path &llc, std::string &ErrMsg ) { // Run LLC to convert the bitcode file into assembly code. std::vector<const char*> args; args.push_back(llc.c_str()); // We will use GCC to assemble the program so set the assembly syntax to AT&T, // regardless of what the target in the bitcode file is. args.push_back("-x86-asm-syntax=att"); args.push_back("-o"); args.push_back(OutputFilename.c_str()); args.push_back(InputFilename.c_str()); args.push_back(0); if (Verbose) { errs() << "Generating Assembly With: \n"; PrintCommand(args); } return sys::Program::ExecuteAndWait(llc, &args[0], 0, 0, 0, 0, &ErrMsg); }
void llvm::DisplayGraph(const sys::Path &Filename, bool wait, GraphProgram::Name program) { std::string ErrMsg; #if HAVE_GRAPHVIZ sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); std::vector<const char*> args; args.push_back(Graphviz.c_str()); args.push_back(Filename.c_str()); args.push_back(0); errs() << "Running 'Graphviz' program... "; if (sys::Program::ExecuteAndWait(Graphviz, &args[0],0,0,0,0,&ErrMsg)) errs() << "Error viewing graph " << Filename.str() << ": " << ErrMsg << "\n"; else Filename.eraseFromDisk(); #elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \ HAVE_TWOPI || HAVE_CIRCO)) sys::Path PSFilename = Filename; PSFilename.appendSuffix("ps"); sys::Path prog; // Set default grapher #if HAVE_CIRCO prog = sys::Path(LLVM_PATH_CIRCO); #endif #if HAVE_TWOPI prog = sys::Path(LLVM_PATH_TWOPI); #endif #if HAVE_NEATO prog = sys::Path(LLVM_PATH_NEATO); #endif #if HAVE_FDP prog = sys::Path(LLVM_PATH_FDP); #endif #if HAVE_DOT prog = sys::Path(LLVM_PATH_DOT); #endif // Find which program the user wants #if HAVE_DOT if (program == GraphProgram::DOT) prog = sys::Path(LLVM_PATH_DOT); #endif #if (HAVE_FDP) if (program == GraphProgram::FDP) prog = sys::Path(LLVM_PATH_FDP); #endif #if (HAVE_NEATO) if (program == GraphProgram::NEATO) prog = sys::Path(LLVM_PATH_NEATO); #endif #if (HAVE_TWOPI) if (program == GraphProgram::TWOPI) prog = sys::Path(LLVM_PATH_TWOPI); #endif #if (HAVE_CIRCO) if (program == GraphProgram::CIRCO) prog = sys::Path(LLVM_PATH_CIRCO); #endif std::vector<const char*> args; args.push_back(prog.c_str()); args.push_back("-Tps"); args.push_back("-Nfontname=Courier"); args.push_back("-Gsize=7.5,10"); args.push_back(Filename.c_str()); args.push_back("-o"); args.push_back(PSFilename.c_str()); args.push_back(0); errs() << "Running '" << prog.str() << "' program... "; if (sys::Program::ExecuteAndWait(prog, &args[0], 0, 0, 0, 0, &ErrMsg)) { errs() << "Error viewing graph " << Filename.str() << ": '" << ErrMsg << "\n"; } else { errs() << " done. \n"; sys::Path gv(LLVM_PATH_GV); args.clear(); args.push_back(gv.c_str()); args.push_back(PSFilename.c_str()); args.push_back("--spartan"); args.push_back(0); ErrMsg.clear(); if (wait) { if (sys::Program::ExecuteAndWait(gv, &args[0],0,0,0,0,&ErrMsg)) errs() << "Error viewing graph: " << ErrMsg << "\n"; Filename.eraseFromDisk(); PSFilename.eraseFromDisk(); } else { sys::Program::ExecuteNoWait(gv, &args[0],0,0,0,&ErrMsg); errs() << "Remember to erase graph files: " << Filename.str() << " " << PSFilename.str() << "\n"; } } #elif HAVE_DOTTY sys::Path dotty(LLVM_PATH_DOTTY); std::vector<const char*> args; args.push_back(dotty.c_str()); args.push_back(Filename.c_str()); args.push_back(0); errs() << "Running 'dotty' program... "; if (sys::Program::ExecuteAndWait(dotty, &args[0],0,0,0,0,&ErrMsg)) { errs() << "Error viewing graph " << Filename.str() << ": " << ErrMsg << "\n"; } else { #ifdef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns return; #endif Filename.eraseFromDisk(); } #endif }
void llvm::DisplayGraph(const sys::Path &Filename) { std::string ErrMsg; #if HAVE_GRAPHVIZ sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); std::vector<const char*> args; args.push_back(Graphviz.c_str()); args.push_back(Filename.c_str()); args.push_back(0); cerr << "Running 'Graphviz' program... " << std::flush; if (sys::Program::ExecuteAndWait(Graphviz, &args[0],0,0,0,0,&ErrMsg)) { cerr << "Error viewing graph: " << ErrMsg << "\n"; } #elif (HAVE_GV && HAVE_DOT) sys::Path PSFilename = Filename; PSFilename.appendSuffix("ps"); sys::Path dot(LLVM_PATH_DOT); std::vector<const char*> args; args.push_back(dot.c_str()); args.push_back("-Tps"); args.push_back("-Nfontname=Courier"); args.push_back("-Gsize=7.5,10"); args.push_back(Filename.c_str()); args.push_back("-o"); args.push_back(PSFilename.c_str()); args.push_back(0); cerr << "Running 'dot' program... " << std::flush; if (sys::Program::ExecuteAndWait(dot, &args[0],0,0,0,0,&ErrMsg)) { cerr << "Error viewing graph: '" << ErrMsg << "\n"; } else { cerr << " done. \n"; sys::Path gv(LLVM_PATH_GV); args.clear(); args.push_back(gv.c_str()); args.push_back(PSFilename.c_str()); args.push_back(0); ErrMsg.clear(); if (sys::Program::ExecuteAndWait(gv, &args[0],0,0,0,0,&ErrMsg)) { cerr << "Error viewing graph: " << ErrMsg << "\n"; } } PSFilename.eraseFromDisk(); #elif HAVE_DOTTY sys::Path dotty(LLVM_PATH_DOTTY); std::vector<const char*> args; args.push_back(dotty.c_str()); args.push_back(Filename.c_str()); args.push_back(0); cerr << "Running 'dotty' program... " << std::flush; if (sys::Program::ExecuteAndWait(dotty, &args[0],0,0,0,0,&ErrMsg)) { cerr << "Error viewing graph: " << ErrMsg << "\n"; } else { #ifdef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns return; #endif } #endif Filename.eraseFromDisk(); }
///Link all modules together and optimize them using IPO. Generate /// native object file using OutputFilename /// Return appropriate LTOStatus. enum LTOStatus LTO::optimizeModules(const std::string &OutputFilename, std::vector<const char *> &exportList, std::string &targetTriple, bool saveTemps, const char *FinalOutputFilename) { if (modules.empty()) return LTO_NO_WORK; std::ios::openmode io_mode = std::ios::out | std::ios::trunc | std::ios::binary; std::string *errMsg = NULL; Module *bigOne = modules[0]; Linker theLinker("LinkTimeOptimizer", bigOne, false); for (unsigned i = 1, e = modules.size(); i != e; ++i) if (theLinker.LinkModules(bigOne, modules[i], errMsg)) return LTO_MODULE_MERGE_FAILURE; // all modules have been handed off to the linker. modules.clear(); sys::Path FinalOutputPath(FinalOutputFilename); FinalOutputPath.eraseSuffix(); switch(CGModel) { case LTO_CGM_Dynamic: Target->setRelocationModel(Reloc::PIC_); break; case LTO_CGM_DynamicNoPIC: Target->setRelocationModel(Reloc::DynamicNoPIC); break; case LTO_CGM_Static: Target->setRelocationModel(Reloc::Static); break; } if (saveTemps) { std::string tempFileName(FinalOutputPath.c_str()); tempFileName += "0.bc"; std::ofstream Out(tempFileName.c_str(), io_mode); WriteBitcodeToFile(bigOne, Out); } // Strip leading underscore because it was added to match names // seen by linker. for (unsigned i = 0, e = exportList.size(); i != e; ++i) { const char *name = exportList[i]; NameToSymbolMap::iterator itr = allSymbols.find(name); if (itr != allSymbols.end()) exportList[i] = allSymbols[name]->getName(); } std::string ErrMsg; sys::Path TempDir = sys::Path::GetTemporaryDirectory(&ErrMsg); if (TempDir.isEmpty()) { cerr << "lto: " << ErrMsg << "\n"; return LTO_WRITE_FAILURE; } sys::Path tmpAsmFilePath(TempDir); if (!tmpAsmFilePath.appendComponent("lto")) { cerr << "lto: " << ErrMsg << "\n"; TempDir.eraseFromDisk(true); return LTO_WRITE_FAILURE; } if (tmpAsmFilePath.createTemporaryFileOnDisk(true, &ErrMsg)) { cerr << "lto: " << ErrMsg << "\n"; TempDir.eraseFromDisk(true); return LTO_WRITE_FAILURE; } sys::RemoveFileOnSignal(tmpAsmFilePath); std::ofstream asmFile(tmpAsmFilePath.c_str(), io_mode); if (!asmFile.is_open() || asmFile.bad()) { if (tmpAsmFilePath.exists()) { tmpAsmFilePath.eraseFromDisk(); TempDir.eraseFromDisk(true); } return LTO_WRITE_FAILURE; } enum LTOStatus status = optimize(bigOne, asmFile, exportList); asmFile.close(); if (status != LTO_OPT_SUCCESS) { tmpAsmFilePath.eraseFromDisk(); TempDir.eraseFromDisk(true); return status; } if (saveTemps) { std::string tempFileName(FinalOutputPath.c_str()); tempFileName += "1.bc"; std::ofstream Out(tempFileName.c_str(), io_mode); WriteBitcodeToFile(bigOne, Out); } targetTriple = bigOne->getTargetTriple(); // Run GCC to assemble and link the program into native code. // // Note: // We can't just assemble and link the file with the system assembler // and linker because we don't know where to put the _start symbol. // GCC mysteriously knows how to do it. const sys::Path gcc = sys::Program::FindProgramByName("gcc"); if (gcc.isEmpty()) { tmpAsmFilePath.eraseFromDisk(); TempDir.eraseFromDisk(true); return LTO_ASM_FAILURE; } std::vector<const char*> args; args.push_back(gcc.c_str()); if (strncmp(targetTriple.c_str(), "i686-apple-", 11) == 0) { args.push_back("-arch"); args.push_back("i386"); } if (strncmp(targetTriple.c_str(), "x86_64-apple-", 13) == 0) { args.push_back("-arch"); args.push_back("x86_64"); } if (strncmp(targetTriple.c_str(), "powerpc-apple-", 14) == 0) { args.push_back("-arch"); args.push_back("ppc"); } if (strncmp(targetTriple.c_str(), "powerpc64-apple-", 16) == 0) { args.push_back("-arch"); args.push_back("ppc64"); } args.push_back("-c"); args.push_back("-x"); args.push_back("assembler"); args.push_back("-o"); args.push_back(OutputFilename.c_str()); args.push_back(tmpAsmFilePath.c_str()); args.push_back(0); if (sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 0, 0, &ErrMsg)) { cerr << "lto: " << ErrMsg << "\n"; return LTO_ASM_FAILURE; } tmpAsmFilePath.eraseFromDisk(); TempDir.eraseFromDisk(true); return LTO_OPT_SUCCESS; }
static int CompileSubprocess(const char **argv, int argc, sys::Path &ResourceDir, bool bugreport, bool versionOnly, sys::Path &apiMapPath) { std::vector<char*> llvmArgs; char apim[] = "-clam-apimap"; llvmArgs.push_back((char*)argv[0]); llvmArgs.push_back(apim); llvmArgs.push_back((char*)apiMapPath.c_str()); // Split args into cc1 and LLVM args, separator is -- int cc1_argc; for (cc1_argc=1;cc1_argc<argc;cc1_argc++) { if (StringRef(argv[cc1_argc]) == "--") { for (int i=cc1_argc+1;i<argc;i++) { llvmArgs.push_back((char*)argv[i]); } break; } } // Initialize CompilerInstance from commandline args CompilerInstance Clang; Clang.setLLVMContext(new llvm::LLVMContext); LLVMInitializeClamBCTargetInfo(); LLVMInitializeClamBCTarget(); TextDiagnosticBuffer DiagsBuffer; Diagnostic Diags(&DiagsBuffer); CompilerInvocation::CreateFromArgs(Clang.getInvocation(), argv+1, argv+cc1_argc, Diags); FrontendOptions &FrontendOpts = Clang.getInvocation().getFrontendOpts(); // Handle --version if (FrontendOpts.ShowVersion || versionOnly) { printVersion(outs(), true); exit(0); } DiagnosticOptions &DiagOpts = Clang.getInvocation().getDiagnosticOpts(); DiagOpts.ShowOptionNames = DiagOpts.ShowColors = 1; DiagOpts.MessageLength = 80;// we are writing to a file DiagOpts.Warnings.push_back("all"); DiagOpts.Warnings.push_back("no-pointer-sign"); Clang.createDiagnostics(argc-1, const_cast<char**>(argv+1)); if (!Clang.hasDiagnostics()) return 2; Clang.getInvocation().getHeaderSearchOpts().ResourceDir = ResourceDir.str(); // Set default options LangOptions &LangOpts = Clang.getInvocation().getLangOpts(); // This is a freestanding environment, without libc, etc. LangOpts.Freestanding = 1; HeaderSearchOptions &HeaderSearchOpts = Clang.getInvocation().getHeaderSearchOpts(); HeaderSearchOpts.UseStandardIncludes = 0; if (bugreport) HeaderSearchOpts.Verbose = 1; if (FrontendOpts.ProgramAction != frontend::PrintPreprocessedInput) FrontendOpts.ProgramAction = frontend::EmitBC; if (bugreport) FrontendOpts.ProgramAction = frontend::PrintPreprocessedInput; // Don't bother freeing of memory on exit FrontendOpts.DisableFree = 1; CodeGenOptions &Opts = Clang.getInvocation().getCodeGenOpts(); Opts.Inlining = CodeGenOptions::OnlyAlwaysInlining; // always generate debug info, so that ClamBC backend can output sourcelevel // diagnostics. Opts.DebugInfo = true; // FIXME: once the verifier can work w/o targetdata, and targetdate opts set // DisableLLVMOpts to true! // This is needed to avoid target-specific optimizations Opts.DisableLLVMOpts = false; AnalyzerOptions &AOpts = Clang.getInvocation().getAnalyzerOpts(); AOpts.AnalysisList.push_back(WarnDeadStores); AOpts.AnalysisList.push_back(WarnUninitVals); AOpts.AnalysisList.push_back(SecuritySyntacticChecks); AOpts.AnalysisList.push_back(WarnSizeofPointer); // Set triple Clang.getInvocation().getTargetOpts().Triple = "clambc-generic-generic"; // Set default include Clang.getInvocation().getPreprocessorOpts().Includes.push_back("bytecode.h"); // Set an LLVM error handler. llvm::llvm_install_error_handler(LLVMErrorHandler, static_cast<void*>(&Clang.getDiagnostics())); DiagsBuffer.FlushDiagnostics(Clang.getDiagnostics()); // If there were any errors in processing arguments, exit now. if (Clang.getDiagnostics().getNumErrors()) return 1; // Create the target instance. //TODO: directly create a clambc target Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); if (!Clang.hasTarget()) return 1; // Inform the target of the language options Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); if (Clang.getHeaderSearchOpts().Verbose) { llvm::errs() << "clang -cc1 version " CLANG_VERSION_STRING << " based upon " << PACKAGE_STRING << " hosted on " << llvm::sys::getHostTriple() << "\n"; // Convert the invocation back to argument strings. std::vector<std::string> InvocationArgs; Clang.getInvocation().toArgs(InvocationArgs); // Dump the converted arguments. llvm::SmallVector<const char*, 32> Invocation2Args; llvm::errs() << "invocation argv :"; for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) { Invocation2Args.push_back(InvocationArgs[i].c_str()); llvm::errs() << " \"" << InvocationArgs[i] << '"'; } llvm::errs() << "\n"; } std::string Input = FrontendOpts.Inputs[0].second; if (Input == "-" && bugreport) return 2; raw_fd_ostream *fd = 0; if (FrontendOpts.ProgramAction == frontend::EmitBC) { // replace output file of compiler with a tempfile, // and save the final output filename. std::string FinalOutput = FrontendOpts.OutputFile; if (FinalOutput.empty()) { if (Input == "-") FinalOutput = "-"; else { sys::Path P(sys::Path(Input).getBasename()); P.appendSuffix("cbc"); FinalOutput = P.str(); } } llvm::raw_fd_ostream *tmpfd; std::string Err2; fd = Clang.createOutputFile(FinalOutput, Err2, false); if (!fd) { Clang.getDiagnostics().Report(clang::diag::err_drv_unable_to_make_temp) << Err2; return 1; } sys::Path P = sys::Path(FinalOutput); P.eraseSuffix(); P.appendSuffix("tmp.bc"); FrontendOpts.OutputFile = P.str(); tmpfd = Clang.createOutputFile(P.str(), Err2, true); if (!tmpfd) { Clang.getDiagnostics().Report(clang::diag::err_drv_unable_to_make_temp) << Err2; return 1; } delete tmpfd; sys::RemoveFileOnSignal(sys::Path(FrontendOpts.OutputFile)); } if (!FrontendOpts.Inputs.empty()) { char srcp[] = "-clambc-src"; llvmArgs.push_back(srcp); llvmArgs.push_back(strdup(Input.c_str())); } // Parse LLVM commandline args cl::ParseCommandLineOptions(llvmArgs.size(), &llvmArgs[0]); std::string re2cpath = getTmpDir(); if (re2cpath.empty()) { llvm::errs()<< "Failed to create temporary file for re2c-out!\n"; return 2; } re2cpath += "/clambc-compiler-re2c-out"; sys::Path TmpRe2C(re2cpath); if (!FrontendOpts.Inputs.empty()) { char re2c_args[] = "--no-generation-date"; char re2c_o[] = "-o"; char name[] = ""; char *args[6] = { name, re2c_args, re2c_o, NULL, NULL, NULL }; args[4] = strdup(Input.c_str()); std::string ErrMsg(""); if (TmpRe2C.createTemporaryFileOnDisk(true, &ErrMsg)) { Clang.getDiagnostics().Report(clang::diag::err_drv_unable_to_make_temp) << ErrMsg; return 1; } sys::RemoveFileOnSignal(TmpRe2C); args[3] = strdup(TmpRe2C.str().c_str()); int ret = re2c_main(5, args); if (ret) { Clang.getDiagnostics().Report(clang::diag::err_drv_command_failed) << "re2c" << ret; return 1; } Input = TmpRe2C.str(); } // Create a file manager object to provide access to and cache the // filesystem. Clang.createFileManager(); // Create the source manager. Clang.createSourceManager(); // Create the preprocessor. Clang.createPreprocessor(); llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(Clang)); if (Act && Act->BeginSourceFile(Clang, Input, false)) { Act->Execute(); Act->EndSourceFile(); } TmpRe2C.eraseFromDisk();// erase tempfile int ret = Clang.getDiagnostics().getNumErrors() != 0; if (ret) return ret; if (FrontendOpts.ProgramAction != frontend::EmitBC) { // stop processing if not compiling a final .cbc file return 0; } ret = compileInternal(FrontendOpts.OutputFile.c_str(), Opts.OptimizationLevel, Opts.OptimizeSize, argv[0], fd, Clang); // Erase temp file, we need to do this here since OutputFile is a tempfile // only if action was EmitBC sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); return ret; }
/// GenerateNative - generates a native object file from the /// specified bytecode file. /// /// Inputs: /// InputFilename - The name of the input bytecode file. /// OutputFilename - The name of the file to generate. /// NativeLinkItems - The native libraries, files, code with which to link /// LibPaths - The list of directories in which to find libraries. /// gcc - The pathname to use for GGC. /// envp - A copy of the process's current environment. /// /// Outputs: /// None. /// /// Returns non-zero value on error. /// static int GenerateNative(const std::string &OutputFilename, const std::string &InputFilename, const Linker::ItemList &LinkItems, const sys::Path &gcc, char ** const envp, std::string& ErrMsg) { // Remove these environment variables from the environment of the // programs that we will execute. It appears that GCC sets these // environment variables so that the programs it uses can configure // themselves identically. // // However, when we invoke GCC below, we want it to use its normal // configuration. Hence, we must sanitize its environment. char ** clean_env = CopyEnv(envp); if (clean_env == NULL) return 1; RemoveEnv("LIBRARY_PATH", clean_env); RemoveEnv("COLLECT_GCC_OPTIONS", clean_env); RemoveEnv("GCC_EXEC_PREFIX", clean_env); RemoveEnv("COMPILER_PATH", clean_env); RemoveEnv("COLLECT_GCC", clean_env); // Run GCC to assemble and link the program into native code. // // Note: // We can't just assemble and link the file with the system assembler // and linker because we don't know where to put the _start symbol. // GCC mysteriously knows how to do it. std::vector<const char*> args; args.push_back(gcc.c_str()); args.push_back("-fno-strict-aliasing"); args.push_back("-O3"); args.push_back("-o"); args.push_back(OutputFilename.c_str()); args.push_back(InputFilename.c_str()); // Add in the library paths for (unsigned index = 0; index < LibPaths.size(); index++) { args.push_back("-L"); args.push_back(LibPaths[index].c_str()); } // Add the requested options for (unsigned index = 0; index < XLinker.size(); index++) { args.push_back(XLinker[index].c_str()); args.push_back(Libraries[index].c_str()); } // Add in the libraries to link. for (unsigned index = 0; index < LinkItems.size(); index++) if (LinkItems[index].first != "crtend") { if (LinkItems[index].second) { std::string lib_name = "-l" + LinkItems[index].first; args.push_back(lib_name.c_str()); } else args.push_back(LinkItems[index].first.c_str()); } args.push_back(0); if (Verbose) { cout << "Generating Native Executable With:\n"; PrintCommand(args); } // Run the compiler to assembly and link together the program. int R = sys::Program::ExecuteAndWait( gcc, &args[0], (const char**)clean_env, 0, 0, 0, &ErrMsg); delete [] clean_env; return R; }
void llvm::DisplayGraph(const sys::Path &Filename, bool wait, GraphProgram::Name program) { wait &= !ViewBackground; std::string ErrMsg; #if HAVE_GRAPHVIZ sys::Path Graphviz(LLVM_PATH_GRAPHVIZ); std::vector<const char*> args; args.push_back(Graphviz.c_str()); args.push_back(Filename.c_str()); args.push_back(0); errs() << "Running 'Graphviz' program... "; if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg)) return; #elif HAVE_XDOT_PY std::vector<const char*> args; args.push_back(LLVM_PATH_XDOT_PY); args.push_back(Filename.c_str()); switch (program) { case GraphProgram::DOT: args.push_back("-f"); args.push_back("dot"); break; case GraphProgram::FDP: args.push_back("-f"); args.push_back("fdp"); break; case GraphProgram::NEATO: args.push_back("-f"); args.push_back("neato");break; case GraphProgram::TWOPI: args.push_back("-f"); args.push_back("twopi");break; case GraphProgram::CIRCO: args.push_back("-f"); args.push_back("circo");break; } args.push_back(0); errs() << "Running 'xdot.py' program... "; if (!ExecGraphViewer(sys::Path(LLVM_PATH_XDOT_PY), args, Filename, wait, ErrMsg)) return; #elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \ HAVE_TWOPI || HAVE_CIRCO)) sys::Path PSFilename = Filename; PSFilename.appendSuffix("ps"); sys::Path prog; // Set default grapher #if HAVE_CIRCO prog = sys::Path(LLVM_PATH_CIRCO); #endif #if HAVE_TWOPI prog = sys::Path(LLVM_PATH_TWOPI); #endif #if HAVE_NEATO prog = sys::Path(LLVM_PATH_NEATO); #endif #if HAVE_FDP prog = sys::Path(LLVM_PATH_FDP); #endif #if HAVE_DOT prog = sys::Path(LLVM_PATH_DOT); #endif // Find which program the user wants #if HAVE_DOT if (program == GraphProgram::DOT) prog = sys::Path(LLVM_PATH_DOT); #endif #if (HAVE_FDP) if (program == GraphProgram::FDP) prog = sys::Path(LLVM_PATH_FDP); #endif #if (HAVE_NEATO) if (program == GraphProgram::NEATO) prog = sys::Path(LLVM_PATH_NEATO); #endif #if (HAVE_TWOPI) if (program == GraphProgram::TWOPI) prog = sys::Path(LLVM_PATH_TWOPI); #endif #if (HAVE_CIRCO) if (program == GraphProgram::CIRCO) prog = sys::Path(LLVM_PATH_CIRCO); #endif std::vector<const char*> args; args.push_back(prog.c_str()); args.push_back("-Tps"); args.push_back("-Nfontname=Courier"); args.push_back("-Gsize=7.5,10"); args.push_back(Filename.c_str()); args.push_back("-o"); args.push_back(PSFilename.c_str()); args.push_back(0); errs() << "Running '" << prog.str() << "' program... "; if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg)) return; sys::Path gv(LLVM_PATH_GV); args.clear(); args.push_back(gv.c_str()); args.push_back(PSFilename.c_str()); args.push_back("--spartan"); args.push_back(0); ErrMsg.clear(); if (!ExecGraphViewer(gv, args, PSFilename, wait, ErrMsg)) return; #elif HAVE_DOTTY sys::Path dotty(LLVM_PATH_DOTTY); std::vector<const char*> args; args.push_back(dotty.c_str()); args.push_back(Filename.c_str()); args.push_back(0); // Dotty spawns another app and doesn't wait until it returns #if defined (__MINGW32__) || defined (_WINDOWS) wait = false; #endif errs() << "Running 'dotty' program... "; if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg)) return; #endif }
/// GenerateNative - generates a native object file from the /// specified bitcode file. /// /// Inputs: /// InputFilename - The name of the input bitcode file. /// OutputFilename - The name of the file to generate. /// NativeLinkItems - The native libraries, files, code with which to link /// LibPaths - The list of directories in which to find libraries. /// FrameworksPaths - The list of directories in which to find frameworks. /// Frameworks - The list of frameworks (dynamic libraries) /// gcc - The pathname to use for GGC. /// envp - A copy of the process's current environment. /// /// Outputs: /// None. /// /// Returns non-zero value on error. /// static int GenerateNative(const std::string &OutputFilename, const std::string &InputFilename, const Linker::ItemList &LinkItems, const sys::Path &gcc, char ** const envp, std::string& ErrMsg) { // Remove these environment variables from the environment of the // programs that we will execute. It appears that GCC sets these // environment variables so that the programs it uses can configure // themselves identically. // // However, when we invoke GCC below, we want it to use its normal // configuration. Hence, we must sanitize its environment. char ** clean_env = CopyEnv(envp); if (clean_env == NULL) return 1; RemoveEnv("LIBRARY_PATH", clean_env); RemoveEnv("COLLECT_GCC_OPTIONS", clean_env); RemoveEnv("GCC_EXEC_PREFIX", clean_env); RemoveEnv("COMPILER_PATH", clean_env); RemoveEnv("COLLECT_GCC", clean_env); // Run GCC to assemble and link the program into native code. // // Note: // We can't just assemble and link the file with the system assembler // and linker because we don't know where to put the _start symbol. // GCC mysteriously knows how to do it. std::vector<std::string> args; args.push_back(gcc.c_str()); args.push_back("-fno-strict-aliasing"); args.push_back("-O3"); args.push_back("-o"); args.push_back(OutputFilename); args.push_back(InputFilename); // Add in the library and framework paths for (unsigned index = 0; index < LibPaths.size(); index++) { args.push_back("-L" + LibPaths[index]); } for (unsigned index = 0; index < FrameworkPaths.size(); index++) { args.push_back("-F" + FrameworkPaths[index]); } // Add the requested options for (unsigned index = 0; index < XLinker.size(); index++) args.push_back(XLinker[index]); // Add in the libraries to link. for (unsigned index = 0; index < LinkItems.size(); index++) if (LinkItems[index].first != "crtend") { if (LinkItems[index].second) args.push_back("-l" + LinkItems[index].first); else args.push_back(LinkItems[index].first); } // Add in frameworks to link. for (unsigned index = 0; index < Frameworks.size(); index++) { args.push_back("-framework"); args.push_back(Frameworks[index]); } // Now that "args" owns all the std::strings for the arguments, call the c_str // method to get the underlying string array. We do this game so that the // std::string array is guaranteed to outlive the const char* array. std::vector<const char *> Args; for (unsigned i = 0, e = args.size(); i != e; ++i) Args.push_back(args[i].c_str()); Args.push_back(0); if (Verbose) { errs() << "Generating Native Executable With:\n"; PrintCommand(Args); } // Run the compiler to assembly and link together the program. int R = sys::Program::ExecuteAndWait( gcc, &Args[0], const_cast<const char **>(clean_env), 0, 0, 0, &ErrMsg); delete [] clean_env; return R; }