sys::Path Tool::OutFilename(const sys::Path& In, const sys::Path& TempDir, bool StopCompilation, const char* OutputSuffix) const { sys::Path Out; if (StopCompilation) { if (!OutputFilename.empty()) { Out.set(OutputFilename); } else if (IsJoin()) { Out.set("a"); Out.appendSuffix(OutputSuffix); } else { Out.set(In.getBasename()); Out.appendSuffix(OutputSuffix); } } else { if (IsJoin()) Out = MakeTempFile(TempDir, "tmp", OutputSuffix); else Out = MakeTempFile(TempDir, In.getBasename(), OutputSuffix); } return Out; }
// recurseDirectories - Implements the "R" modifier. This function scans through // the Paths vector (built by buildPaths, below) and replaces any directories it // finds with all the files in that directory (recursively). It uses the // sys::Path::getDirectoryContent method to perform the actual directory scans. bool recurseDirectories(const sys::Path& path, std::set<sys::Path>& result, std::string* ErrMsg) { result.clear(); if (RecurseDirectories) { std::set<sys::Path> content; if (path.getDirectoryContents(content, ErrMsg)) return true; for (std::set<sys::Path>::iterator I = content.begin(), E = content.end(); I != E; ++I) { // Make sure it exists and is a directory sys::PathWithStatus PwS(*I); const sys::FileStatus *Status = PwS.getFileStatus(false, ErrMsg); if (!Status) return true; if (Status->isDir) { std::set<sys::Path> moreResults; if (recurseDirectories(*I, moreResults, ErrMsg)) return true; result.insert(moreResults.begin(), moreResults.end()); } else { result.insert(*I); } } } return false; }
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 }
// Execute the graph viewer. Return true if successful. static bool LLVM_ATTRIBUTE_UNUSED ExecGraphViewer(const sys::Path &ExecPath, std::vector<const char*> &args, const sys::Path &Filename, bool wait, std::string &ErrMsg) { if (wait) { if (sys::Program::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) { errs() << "Error: " << ErrMsg << "\n"; return false; } Filename.eraseFromDisk(); errs() << " done. \n"; } else { sys::Program::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg); errs() << "Remember to erase graph file: " << Filename.str() << "\n"; } return true; }
// 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>(); }
// 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; const std::string &FNS = FN.toString(); std::auto_ptr<MemoryBuffer> Buffer(MemoryBuffer::getFileOrSTDIN(FNS.c_str())); if (Buffer.get()) Result = ParseBitcodeFile(Buffer.get(), &ParseErrorMessage); else ParseErrorMessage = "Error reading file '" + FNS + "'"; if (Result) return std::auto_ptr<Module>(Result); Error = "Bitcode file '" + FN.toString() + "' could not be loaded"; if (ParseErrorMessage.size()) Error += ": " + ParseErrorMessage; return std::auto_ptr<Module>(); }
// Insert a file into the archive before some other member. This also takes care // of extracting the necessary flags and information from the file. bool Archive::addFileBefore(const sys::Path& filePath, iterator where, std::string* ErrMsg) { bool Exists; if (sys::fs::exists(filePath.str(), Exists) || !Exists) { if (ErrMsg) *ErrMsg = "Can not add a non-existent file to archive"; return true; } ArchiveMember* mbr = new ArchiveMember(this); mbr->data = 0; mbr->path = filePath; const sys::FileStatus *FSInfo = mbr->path.getFileStatus(false, ErrMsg); if (!FSInfo) { delete mbr; return true; } mbr->info = *FSInfo; unsigned flags = 0; bool hasSlash = filePath.str().find('/') != std::string::npos; if (hasSlash) flags |= ArchiveMember::HasPathFlag; if (hasSlash || filePath.str().length() > 15) flags |= ArchiveMember::HasLongFilenameFlag; sys::fs::file_magic type; if (sys::fs::identify_magic(mbr->path.str(), type)) type = sys::fs::file_magic::unknown; switch (type) { case sys::fs::file_magic::bitcode: flags |= ArchiveMember::BitcodeFlag; break; default: break; } mbr->flags = flags; members.insert(where,mbr); return false; }
// 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; }
// Insert a file into the archive before some other member. This also takes care // of extracting the necessary flags and information from the file. bool Archive::addFileBefore(const sys::Path& filePath, iterator where, std::string* ErrMsg) { if (!filePath.exists()) { if (ErrMsg) *ErrMsg = "Can not add a non-existent file to archive"; return true; } ArchiveMember* mbr = new ArchiveMember(this); mbr->data = 0; mbr->path = filePath; const sys::FileStatus *FSInfo = mbr->path.getFileStatus(false, ErrMsg); if (!FSInfo) { delete mbr; return true; } mbr->info = *FSInfo; unsigned flags = 0; bool hasSlash = filePath.str().find('/') != std::string::npos; if (hasSlash) flags |= ArchiveMember::HasPathFlag; if (hasSlash || filePath.str().length() > 15) flags |= ArchiveMember::HasLongFilenameFlag; std::string magic; mbr->path.getMagicNumber(magic,4); switch (sys::IdentifyFileType(magic.c_str(),4)) { case sys::Bitcode_FileType: flags |= ArchiveMember::BitcodeFlag; break; default: break; } mbr->flags = flags; members.insert(where,mbr); return false; }
/// 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; }
/// 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); }
/// 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) { 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(); }
/// LinkInFile - opens a bitcode file and links in all objects which /// provide symbols that are currently undefined. /// /// Inputs: /// File - The pathname of the bitcode file. /// /// Outputs: /// ErrorMessage - A C++ string detailing what error occurred, if any. /// /// Return Value: /// TRUE - An error occurred. /// FALSE - No errors. /// bool Linker::LinkInFile(const sys::Path &File, bool &is_native) { is_native = false; // Check for a file of name "-", which means "read standard input" if (File.toString() == "-") { std::auto_ptr<Module> M; if (MemoryBuffer *Buffer = MemoryBuffer::getSTDIN()) { M.reset(ParseBitcodeFile(Buffer, Context, &Error)); delete Buffer; if (M.get()) if (!LinkInModule(M.get(), &Error)) return false; } else Error = "standard input is empty"; return error("Cannot link stdin: " + Error); } // Make sure we can at least read the file if (!File.canRead()) return error("Cannot find linker input '" + File.toString() + "'"); // If its an archive, try to link it in std::string Magic; File.getMagicNumber(Magic, 64); switch (sys::IdentifyFileType(Magic.c_str(), 64)) { default: llvm_unreachable("Bad file type identification"); case sys::Unknown_FileType: return warning("Ignoring file '" + File.toString() + "' because does not contain bitcode."); case sys::Archive_FileType: // A user may specify an ar archive without -l, perhaps because it // is not installed as a library. Detect that and link the archive. verbose("Linking archive file '" + File.toString() + "'"); if (LinkInArchive(File, is_native)) return true; break; case sys::Bitcode_FileType: { verbose("Linking bitcode file '" + File.toString() + "'"); std::auto_ptr<Module> M(LoadObject(File)); if (M.get() == 0) return error("Cannot load file '" + File.toString() + "': " + Error); if (LinkInModule(M.get(), &Error)) return error("Cannot link file '" + File.toString() + "': " + Error); verbose("Linked in file '" + File.toString() + "'"); break; } case sys::ELF_Relocatable_FileType: case sys::ELF_SharedObject_FileType: case sys::Mach_O_Object_FileType: case sys::Mach_O_FixedVirtualMemorySharedLib_FileType: case sys::Mach_O_DynamicallyLinkedSharedLib_FileType: case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType: case sys::COFF_FileType: is_native = true; break; } return false; }
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 }
/// 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; }
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 }
// This method allows an ArchiveMember to be replaced with the data for a // different file, presumably as an update to the member. It also makes sure // the flags are reset correctly. bool ArchiveMember::replaceWith(const sys::Path& newFile, std::string* ErrMsg) { bool Exists; if (sys::fs::exists(newFile.str(), Exists) || !Exists) { if (ErrMsg) *ErrMsg = "Can not replace an archive member with a non-existent file"; return true; } data = 0; path = newFile; // SVR4 symbol tables have an empty name if (path.str() == ARFILE_SVR4_SYMTAB_NAME) flags |= SVR4SymbolTableFlag; else flags &= ~SVR4SymbolTableFlag; // BSD4.4 symbol tables have a special name if (path.str() == ARFILE_BSD4_SYMTAB_NAME) flags |= BSD4SymbolTableFlag; else flags &= ~BSD4SymbolTableFlag; // LLVM symbol tables have a very specific name if (path.str() == ARFILE_LLVM_SYMTAB_NAME) flags |= LLVMSymbolTableFlag; else flags &= ~LLVMSymbolTableFlag; // String table name if (path.str() == ARFILE_STRTAB_NAME) flags |= StringTableFlag; else flags &= ~StringTableFlag; // If it has a slash then it has a path bool hasSlash = path.str().find('/') != std::string::npos; if (hasSlash) flags |= HasPathFlag; else flags &= ~HasPathFlag; // If it has a slash or its over 15 chars then its a long filename format if (hasSlash || path.str().length() > 15) flags |= HasLongFilenameFlag; else flags &= ~HasLongFilenameFlag; // Get the signature and status info const char* signature = (const char*) data; SmallString<4> magic; if (!signature) { sys::fs::get_magic(path.str(), magic.capacity(), magic); signature = magic.c_str(); const sys::FileStatus *FSinfo = path.getFileStatus(false, ErrMsg); if (FSinfo) info = *FSinfo; else return true; } // Determine what kind of file it is. switch (sys::IdentifyFileType(signature,4)) { case sys::Bitcode_FileType: flags |= BitcodeFlag; break; default: flags &= ~BitcodeFlag; break; } return false; }
/// LinkInFile - opens a bitcode file and links in all objects which /// provide symbols that are currently undefined. /// /// Inputs: /// File - The pathname of the bitcode file. /// /// Outputs: /// ErrorMessage - A C++ string detailing what error occurred, if any. /// /// Return Value: /// TRUE - An error occurred. /// FALSE - No errors. /// bool Linker::LinkInFile(const sys::Path &File, bool &is_native) { is_native = false; // Check for a file of name "-", which means "read standard input" if (File.str() == "-") { std::auto_ptr<Module> M; OwningPtr<MemoryBuffer> Buffer; error_code ec; if (!(ec = MemoryBuffer::getSTDIN(Buffer))) { if (!Buffer->getBufferSize()) { Error = "standard input is empty"; } else { M.reset(ParseBitcodeFile(Buffer.get(), Context, &Error)); if (M.get()) if (!LinkInModule(M.get(), &Error)) return false; } } return error("Cannot link stdin: " + ec.message()); } // Determine what variety of file it is. std::string Magic; if (!File.getMagicNumber(Magic, 512)) return error("Cannot find linker input '" + File.str() + "'"); switch (sys::IdentifyFileType(Magic.c_str(), 512)) { default: llvm_unreachable("Bad file type identification"); case sys::Unknown_FileType: return warning("Ignoring file '" + File.str() + "' because does not contain bitcode."); case sys::Archive_FileType: // A user may specify an ar archive without -l, perhaps because it // is not installed as a library. Detect that and link the archive. if (LinkInArchive(File, is_native)) return true; break; case sys::Bitcode_FileType: { verbose("Linking bitcode file '" + File.str() + "'"); std::auto_ptr<Module> M(LoadObject(File)); if (M.get() == 0) return error("Cannot load file '" + File.str() + "': " + Error); if (LinkInModule(M.get(), &Error)) return error("Cannot link file '" + File.str() + "': " + Error); verbose("Linked in file '" + File.str() + "'"); break; } case sys::ELF_Relocatable_FileType: case sys::ELF_SharedObject_FileType: case sys::Mach_O_Object_FileType: case sys::Mach_O_FixedVirtualMemorySharedLib_FileType: case sys::Mach_O_DynamicallyLinkedSharedLib_FileType: case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType: case sys::COFF_FileType: is_native = true; break; } return false; }
/// LinkInArchive - opens an archive library and link in all objects which /// provide symbols that are currently undefined. /// /// Inputs: /// Filename - The pathname of the archive. /// /// Return Value: /// TRUE - An error occurred. /// FALSE - No errors. bool Linker::LinkInArchive(const sys::Path &Filename, bool &is_native) { // Make sure this is an archive file we're dealing with if (!Filename.isArchive()) return error("File '" + Filename.toString() + "' is not an archive."); // Open the archive file verbose("Linking archive file '" + Filename.toString() + "'"); // Find all of the symbols currently undefined in the bitcode program. // If all the symbols are defined, the program is complete, and there is // no reason to link in any archive files. std::set<std::string> UndefinedSymbols; GetAllUndefinedSymbols(Composite, UndefinedSymbols); if (UndefinedSymbols.empty()) { verbose("No symbols undefined, skipping library '" + Filename.toString() + "'"); return false; // No need to link anything in! } std::string ErrMsg; std::auto_ptr<Archive> AutoArch ( Archive::OpenAndLoadSymbols(Filename, Context, &ErrMsg)); Archive* arch = AutoArch.get(); if (!arch) return error("Cannot read archive '" + Filename.toString() + "': " + ErrMsg); if (!arch->isBitcodeArchive()) { is_native = true; return false; } is_native = false; // Save a set of symbols that are not defined by the archive. Since we're // entering a loop, there's no point searching for these multiple times. This // variable is used to "set_subtract" from the set of undefined symbols. std::set<std::string> NotDefinedByArchive; // Save the current set of undefined symbols, because we may have to make // multiple passes over the archive: std::set<std::string> CurrentlyUndefinedSymbols; do { CurrentlyUndefinedSymbols = UndefinedSymbols; // Find the modules we need to link into the target module std::set<ModuleProvider*> Modules; if (!arch->findModulesDefiningSymbols(UndefinedSymbols, Modules, &ErrMsg)) return error("Cannot find symbols in '" + Filename.toString() + "': " + ErrMsg); // If we didn't find any more modules to link this time, we are done // searching this archive. if (Modules.empty()) break; // Any symbols remaining in UndefinedSymbols after // findModulesDefiningSymbols are ones that the archive does not define. So // we add them to the NotDefinedByArchive variable now. NotDefinedByArchive.insert(UndefinedSymbols.begin(), UndefinedSymbols.end()); // Loop over all the ModuleProviders that we got back from the archive for (std::set<ModuleProvider*>::iterator I=Modules.begin(), E=Modules.end(); I != E; ++I) { // Get the module we must link in. std::string moduleErrorMsg; std::auto_ptr<Module> AutoModule((*I)->releaseModule( &moduleErrorMsg )); if (!moduleErrorMsg.empty()) return error("Could not load a module: " + moduleErrorMsg); Module* aModule = AutoModule.get(); if (aModule != NULL) { verbose(" Linking in module: " + aModule->getModuleIdentifier()); // Link it in if (LinkInModule(aModule, &moduleErrorMsg)) { return error("Cannot link in module '" + aModule->getModuleIdentifier() + "': " + moduleErrorMsg); } } } // Get the undefined symbols from the aggregate module. This recomputes the // symbols we still need after the new modules have been linked in. GetAllUndefinedSymbols(Composite, UndefinedSymbols); // At this point we have two sets of undefined symbols: UndefinedSymbols // which holds the undefined symbols from all the modules, and // NotDefinedByArchive which holds symbols we know the archive doesn't // define. There's no point searching for symbols that we won't find in the // archive so we subtract these sets. set_subtract(UndefinedSymbols, NotDefinedByArchive); // If there's no symbols left, no point in continuing to search the // archive. if (UndefinedSymbols.empty()) break; } while (CurrentlyUndefinedSymbols != UndefinedSymbols); return false; }
/// 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; }
///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; }