//===- CompilerDriver.cpp - The LLVM Compiler Driver ------------*- C++ -*-===// // // // The LLVM Compiler Infrastructure // // This file was developed by Reid Spencer and is distributed under the // University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the bulk of the LLVM Compiler Driver (llvmc). // //===----------------------------------------------------------------------===// #include "CompilerDriver.h" #include "ConfigLexer.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" #include "llvm/System/Signals.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/alloca.h" #include using namespace llvm; namespace { void WriteAction(CompilerDriver::Action* action ) { std::cerr << action->program.c_str(); std::vector::const_iterator I = action->args.begin(); while (I != action->args.end()) { std::cerr << ' ' << *I; ++I; } std::cerr << '\n'; } void DumpAction(CompilerDriver::Action* action) { std::cerr << "command = " << action->program.c_str(); std::vector::const_iterator I = action->args.begin(); while (I != action->args.end()) { std::cerr << ' ' << *I; ++I; } std::cerr << '\n'; std::cerr << "flags = " << action->flags << '\n'; } void DumpConfigData(CompilerDriver::ConfigData* cd, const std::string& type ){ std::cerr << "Configuration Data For '" << cd->langName << "' (" << type << ")\n"; std::cerr << "PreProcessor: "; DumpAction(&cd->PreProcessor); std::cerr << "Translator: "; DumpAction(&cd->Translator); std::cerr << "Optimizer: "; DumpAction(&cd->Optimizer); std::cerr << "Assembler: "; DumpAction(&cd->Assembler); std::cerr << "Linker: "; DumpAction(&cd->Linker); } static bool GetBytecodeDependentLibraries(const std::string &fname, Module::LibraryListType& deplibs, std::string* ErrMsg) { ModuleProvider *MP = 0; if (MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(fname)) { MP = getBitcodeModuleProvider(Buffer); if (MP == 0) delete Buffer; } if (!MP) { deplibs.clear(); return true; } deplibs = MP->getModule()->getLibraries(); delete MP; return false; } class CompilerDriverImpl : public CompilerDriver { /// @name Constructors /// @{ public: CompilerDriverImpl(ConfigDataProvider& confDatProv ) : cdp(&confDatProv) , finalPhase(LINKING) , optLevel(OPT_FAST_COMPILE) , Flags(0) , machine() , LibraryPaths() , TempDir() , AdditionalArgs() { AdditionalArgs.reserve(NUM_PHASES); StringVector emptyVec; for (unsigned i = 0; i < NUM_PHASES; ++i) AdditionalArgs.push_back(emptyVec); } virtual ~CompilerDriverImpl() { cleanup(); cdp = 0; LibraryPaths.clear(); IncludePaths.clear(); Defines.clear(); TempDir.clear(); AdditionalArgs.clear(); fOptions.clear(); MOptions.clear(); WOptions.clear(); } /// @} /// @name Methods /// @{ public: virtual void setFinalPhase(Phases phase) { finalPhase = phase; } virtual void setOptimization(OptimizationLevels level) { optLevel = level; } virtual void setDriverFlags(unsigned flags) { Flags = flags & DRIVER_FLAGS_MASK; } virtual void setOutputMachine(const std::string& machineName) { machine = machineName; } virtual void setPhaseArgs(Phases phase, const StringVector& opts) { assert(phase <= LINKING && phase >= PREPROCESSING); AdditionalArgs[phase] = opts; } virtual void setIncludePaths(const StringVector& paths) { StringVector::const_iterator I = paths.begin(); StringVector::const_iterator E = paths.end(); while (I != E) { sys::Path tmp; tmp.set(*I); IncludePaths.push_back(tmp); ++I; } } virtual void setSymbolDefines(const StringVector& defs) { Defines = defs; } virtual void setLibraryPaths(const StringVector& paths) { StringVector::const_iterator I = paths.begin(); StringVector::const_iterator E = paths.end(); while (I != E) { sys::Path tmp; tmp.set(*I); LibraryPaths.push_back(tmp); ++I; } } virtual void addLibraryPath(const sys::Path& libPath) { LibraryPaths.push_back(libPath); } virtual void addToolPath(const sys::Path& toolPath) { ToolPaths.push_back(toolPath); } virtual void setfPassThrough(const StringVector& fOpts) { fOptions = fOpts; } /// @brief Set the list of -M options to be passed through virtual void setMPassThrough(const StringVector& MOpts) { MOptions = MOpts; } /// @brief Set the list of -W options to be passed through virtual void setWPassThrough(const StringVector& WOpts) { WOptions = WOpts; } /// @} /// @name Functions /// @{ private: bool isSet(DriverFlags flag) { return 0 != ((flag & DRIVER_FLAGS_MASK) & Flags); } void cleanup() { if (!isSet(KEEP_TEMPS_FLAG)) { const sys::FileStatus *Status = TempDir.getFileStatus(); if (Status && Status->isDir) TempDir.eraseFromDisk(/*remove_contents=*/true); } else { std::cout << "Temporary files are in " << TempDir << "\n"; } } sys::Path MakeTempFile(const std::string& basename, const std::string& suffix, std::string* ErrMsg) { if (TempDir.isEmpty()) { TempDir = sys::Path::GetTemporaryDirectory(ErrMsg); if (TempDir.isEmpty()) return sys::Path(); sys::RemoveDirectoryOnSignal(TempDir); } sys::Path result(TempDir); if (!result.appendComponent(basename)) { if (ErrMsg) *ErrMsg = basename + ": can't use this file name"; return sys::Path(); } if (!result.appendSuffix(suffix)) { if (ErrMsg) *ErrMsg = suffix + ": can't use this file suffix"; return sys::Path(); } return result; } Action* GetAction(ConfigData* cd, const sys::Path& input, const sys::Path& output, Phases phase) { Action* pat = 0; ///< The pattern/template for the action Action* action = new Action; ///< The actual action to execute // Get the action pattern switch (phase) { case PREPROCESSING: pat = &cd->PreProcessor; break; case TRANSLATION: pat = &cd->Translator; break; case OPTIMIZATION: pat = &cd->Optimizer; break; case ASSEMBLY: pat = &cd->Assembler; break; case LINKING: pat = &cd->Linker; break; default: assert(!"Invalid driver phase!"); break; } assert(pat != 0 && "Invalid command pattern"); // Copy over some pattern things that don't need to change action->flags = pat->flags; // See if program starts with wildcard... std::string programName=pat->program.toString(); if (programName[0] == '%' && programName.length() >2) { switch(programName[1]){ case 'b': if (programName.substr(0,8) == "%bindir%") { std::string tmp(LLVM_BINDIR); tmp.append(programName.substr(8)); pat->program.set(tmp); } break; case 'l': if (programName.substr(0,12) == "%llvmgccdir%"){ std::string tmp(LLVMGCCDIR); tmp.append(programName.substr(12)); pat->program.set(tmp); }else if (programName.substr(0,13) == "%llvmgccarch%"){ std::string tmp(LLVMGCCARCH); tmp.append(programName.substr(13)); pat->program.set(tmp); }else if (programName.substr(0,9) == "%llvmgcc%"){ std::string tmp(LLVMGCC); tmp.append(programName.substr(9)); pat->program.set(tmp); }else if (programName.substr(0,9) == "%llvmgxx%"){ std::string tmp(LLVMGXX); tmp.append(programName.substr(9)); pat->program.set(tmp); }else if (programName.substr(0,9) == "%llvmcc1%"){ std::string tmp(LLVMCC1); tmp.append(programName.substr(9)); pat->program.set(tmp); }else if (programName.substr(0,13) == "%llvmcc1plus%"){ std::string tmp(LLVMCC1PLUS); tmp.append(programName.substr(13)); pat->program.set(tmp); }else if (programName.substr(0,8) == "%libdir%") { std::string tmp(LLVM_LIBDIR); tmp.append(programName.substr(8)); pat->program.set(tmp); } break; } } action->program = pat->program; // Do the substitutions from the pattern to the actual StringVector::iterator PI = pat->args.begin(); StringVector::iterator PE = pat->args.end(); while (PI != PE) { if ((*PI)[0] == '%' && PI->length() >2) { bool found = true; switch ((*PI)[1]) { case 'a': if (*PI == "%args%") { if (AdditionalArgs.size() > unsigned(phase)) if (!AdditionalArgs[phase].empty()) { // Get specific options for each kind of action type StringVector& addargs = AdditionalArgs[phase]; // Add specific options for each kind of action type action->args.insert(action->args.end(), addargs.begin(), addargs.end()); } } else found = false; break; case 'b': if (*PI == "%bindir%") { std::string tmp(*PI); tmp.replace(0,8,LLVM_BINDIR); action->args.push_back(tmp); } else found = false; break; case 'd': if (*PI == "%defs%") { StringVector::iterator I = Defines.begin(); StringVector::iterator E = Defines.end(); while (I != E) { action->args.push_back( std::string("-D") + *I); ++I; } } else found = false; break; case 'f': if (*PI == "%fOpts%") { if (!fOptions.empty()) action->args.insert(action->args.end(), fOptions.begin(), fOptions.end()); } else found = false; break; case 'i': if (*PI == "%in%") { action->args.push_back(input.toString()); } else if (*PI == "%incls%") { PathVector::iterator I = IncludePaths.begin(); PathVector::iterator E = IncludePaths.end(); while (I != E) { action->args.push_back( std::string("-I") + I->toString() ); ++I; } } else found = false; break; case 'l': if ((*PI)[1] == 'l') { std::string tmp(*PI); if (*PI == "%llvmgccdir%") tmp.replace(0,12,LLVMGCCDIR); else if (*PI == "%llvmgccarch%") tmp.replace(0,13,LLVMGCCARCH); else if (*PI == "%llvmgcc%") tmp.replace(0,9,LLVMGCC); else if (*PI == "%llvmgxx%") tmp.replace(0,9,LLVMGXX); else if (*PI == "%llvmcc1%") tmp.replace(0,9,LLVMCC1); else if (*PI == "%llvmcc1plus%") tmp.replace(0,9,LLVMCC1); else found = false; if (found) action->args.push_back(tmp); } else if (*PI == "%libs%") { PathVector::iterator I = LibraryPaths.begin(); PathVector::iterator E = LibraryPaths.end(); while (I != E) { action->args.push_back( std::string("-L") + I->toString() ); ++I; } } else if (*PI == "%libdir%") { std::string tmp(*PI); tmp.replace(0,8,LLVM_LIBDIR); action->args.push_back(tmp); } else found = false; break; case 'o': if (*PI == "%out%") { action->args.push_back(output.toString()); } else if (*PI == "%opt%") { if (!isSet(EMIT_RAW_FLAG)) { if (cd->opts.size() > static_cast(optLevel) && !cd->opts[optLevel].empty()) action->args.insert(action->args.end(), cd->opts[optLevel].begin(), cd->opts[optLevel].end()); else throw std::string("Optimization options for level ") + utostr(unsigned(optLevel)) + " were not specified"; } } else found = false; break; case 's': if (*PI == "%stats%") { if (isSet(SHOW_STATS_FLAG)) action->args.push_back("-stats"); } else found = false; break; case 't': if (*PI == "%target%") { action->args.push_back(std::string("-march=") + machine); } else if (*PI == "%time%") { if (isSet(TIME_PASSES_FLAG)) action->args.push_back("-time-passes"); } else found = false; break; case 'v': if (*PI == "%verbose%") { if (isSet(VERBOSE_FLAG)) action->args.push_back("-v"); } else found = false; break; case 'M': if (*PI == "%Mopts%") { if (!MOptions.empty()) action->args.insert(action->args.end(), MOptions.begin(), MOptions.end()); } else found = false; break; case 'W': if (*PI == "%Wopts%") { for (StringVector::iterator I = WOptions.begin(), E = WOptions.end(); I != E ; ++I ) { action->args.push_back(std::string("-W") + *I); } } else found = false; break; default: found = false; break; } if (!found) { // Did it even look like a substitution? if (PI->length()>1 && (*PI)[0] == '%' && (*PI)[PI->length()-1] == '%') { throw std::string("Invalid substitution token: '") + *PI + "' for command '" + pat->program.toString() + "'"; } else if (!PI->empty()) { // It's not a legal substitution, just pass it through action->args.push_back(*PI); } } } else if (!PI->empty()) { // Its not a substitution, just put it in the action action->args.push_back(*PI); } PI++; } // Finally, we're done return action; } int DoAction(Action*action, std::string& ErrMsg) { assert(action != 0 && "Invalid Action!"); if (isSet(VERBOSE_FLAG)) WriteAction(action); if (!isSet(DRY_RUN_FLAG)) { sys::Path progpath = sys::Program::FindProgramByName( action->program.toString()); if (progpath.isEmpty()) throw std::string("Can't find program '" + action->program.toString()+"'"); else if (progpath.canExecute()) action->program = progpath; else throw std::string("Program '"+action->program.toString()+ "' is not executable."); // Invoke the program const char** Args = (const char**) alloca(sizeof(const char*)*(action->args.size()+2)); Args[0] = action->program.toString().c_str(); for (unsigned i = 1; i <= action->args.size(); ++i) Args[i] = action->args[i-1].c_str(); Args[action->args.size()+1] = 0; // null terminate list. if (isSet(TIME_ACTIONS_FLAG)) { Timer timer(action->program.toString()); timer.startTimer(); int resultCode = sys::Program::ExecuteAndWait(action->program, Args,0,0,0,0, &ErrMsg); timer.stopTimer(); timer.print(timer,std::cerr); return resultCode; } else return sys::Program::ExecuteAndWait(action->program, Args, 0,0,0,0, &ErrMsg); } return 0; } /// This method tries various variants of a linkage item's file /// name to see if it can find an appropriate file to link with /// in the directories of the LibraryPaths. llvm::sys::Path GetPathForLinkageItem(const std::string& link_item, bool native = false) { sys::Path fullpath; fullpath.set(link_item); if (fullpath.canRead()) return fullpath; for (PathVector::iterator PI = LibraryPaths.begin(), PE = LibraryPaths.end(); PI != PE; ++PI) { fullpath.set(PI->toString()); fullpath.appendComponent(link_item); if (fullpath.canRead()) return fullpath; if (native) { fullpath.appendSuffix("a"); } else { fullpath.appendSuffix("bc"); if (fullpath.canRead()) return fullpath; fullpath.eraseSuffix(); fullpath.appendSuffix("o"); if (fullpath.canRead()) return fullpath; fullpath = *PI; fullpath.appendComponent(std::string("lib") + link_item); fullpath.appendSuffix("a"); if (fullpath.canRead()) return fullpath; fullpath.eraseSuffix(); fullpath.appendSuffix("so"); if (fullpath.canRead()) return fullpath; } } // Didn't find one. fullpath.clear(); return fullpath; } /// This method processes a linkage item. The item could be a /// Bytecode file needing translation to native code and that is /// dependent on other bytecode libraries, or a native code /// library that should just be linked into the program. bool ProcessLinkageItem(const llvm::sys::Path& link_item, SetVector& set, std::string& err) { // First, see if the unadorned file name is not readable. If so, // we must track down the file in the lib search path. sys::Path fullpath; if (!link_item.canRead()) { // look for the library using the -L arguments specified // on the command line. fullpath = GetPathForLinkageItem(link_item.toString()); // If we didn't find the file in any of the library search paths // we have to bail. No where else to look. if (fullpath.isEmpty()) { err = std::string("Can't find linkage item '") + link_item.toString() + "'"; return false; } } else { fullpath = link_item; } // If we got here fullpath is the path to the file, and its readable. set.insert(fullpath); // If its an LLVM bytecode file ... if (fullpath.isBytecodeFile()) { // Process the dependent libraries recursively Module::LibraryListType modlibs; if (GetBytecodeDependentLibraries(fullpath.toString(),modlibs, &err)) { // Traverse the dependent libraries list Module::lib_iterator LI = modlibs.begin(); Module::lib_iterator LE = modlibs.end(); while ( LI != LE ) { if (!ProcessLinkageItem(sys::Path(*LI),set,err)) { if (err.empty()) { err = std::string("Library '") + *LI + "' is not valid for linking but is required by file '" + fullpath.toString() + "'"; } else { err += " which is required by file '" + fullpath.toString() + "'"; } return false; } ++LI; } } else if (err.empty()) { err = std::string( "The dependent libraries could not be extracted from '") + fullpath.toString(); return false; } else return false; } return true; } /// @} /// @name Methods /// @{ public: virtual int execute(const InputList& InpList, const sys::Path& Output, std::string& ErrMsg ) { try { // Echo the configuration of options if we're running verbose if (isSet(DEBUG_FLAG)) { std::cerr << "Compiler Driver Options:\n"; std::cerr << "DryRun = " << isSet(DRY_RUN_FLAG) << "\n"; std::cerr << "Verbose = " << isSet(VERBOSE_FLAG) << " \n"; std::cerr << "TimeActions = " << isSet(TIME_ACTIONS_FLAG) << "\n"; std::cerr << "TimePasses = " << isSet(TIME_PASSES_FLAG) << "\n"; std::cerr << "ShowStats = " << isSet(SHOW_STATS_FLAG) << "\n"; std::cerr << "EmitRawCode = " << isSet(EMIT_RAW_FLAG) << "\n"; std::cerr << "EmitNativeCode = " << isSet(EMIT_NATIVE_FLAG) << "\n"; std::cerr << "KeepTemps = " << isSet(KEEP_TEMPS_FLAG) << "\n"; std::cerr << "OutputMachine = " << machine << "\n"; InputList::const_iterator I = InpList.begin(); while ( I != InpList.end() ) { std::cerr << "Input: " << I->first << "(" << I->second << ")\n"; ++I; } std::cerr << "Output: " << Output << "\n"; } // If there's no input, we're done. if (InpList.empty()) throw std::string("Nothing to compile."); // If they are asking for linking and didn't provide an output // file then its an error (no way for us to "make up" a meaningful // file name based on the various linker input files). if (finalPhase == LINKING && Output.isEmpty()) throw std::string( "An output file name must be specified for linker output"); // If they are not asking for linking, provided an output file and // there is more than one input file, its an error if (finalPhase != LINKING && !Output.isEmpty() && InpList.size() > 1) throw std::string("An output file name cannot be specified ") + "with more than one input file name when not linking"; // This vector holds all the resulting actions of the following loop. std::vector actions; /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases // for each input item SetVector LinkageItems; StringVector LibFiles; InputList::const_iterator I = InpList.begin(); for (InputList::const_iterator I = InpList.begin(), E = InpList.end(); I != E; ++I ) { // Get the suffix of the file name const std::string& ftype = I->second; // If its a library, bytecode file, or object file, save // it for linking below and short circuit the // pre-processing/translation/assembly phases if (ftype.empty() || ftype == "o" || ftype == "bc" || ftype=="a") { // We shouldn't get any of these types of files unless we're // later going to link. Enforce this limit now. if (finalPhase != LINKING) { throw std::string( "Pre-compiled objects found but linking not requested"); } if (ftype.empty()) LibFiles.push_back(I->first.toString()); else LinkageItems.insert(I->first); continue; // short circuit remainder of loop } // At this point, we know its something we need to translate // and/or optimize. See if we can get the configuration data // for this kind of file. ConfigData* cd = cdp->ProvideConfigData(I->second); if (cd == 0) throw std::string("Files of type '") + I->second + "' are not recognized."; if (isSet(DEBUG_FLAG)) DumpConfigData(cd,I->second); // Add the config data's library paths to the end of the list for (StringVector::iterator LPI = cd->libpaths.begin(), LPE = cd->libpaths.end(); LPI != LPE; ++LPI){ LibraryPaths.push_back(sys::Path(*LPI)); } // Initialize the input and output files sys::Path InFile(I->first); sys::Path OutFile(I->first.getBasename()); // PRE-PROCESSING PHASE Action& action = cd->PreProcessor; // Get the preprocessing action, if needed, or error if appropriate if (!action.program.isEmpty()) { if (action.isSet(REQUIRED_FLAG) || finalPhase == PREPROCESSING) { if (finalPhase == PREPROCESSING) { if (Output.isEmpty()) { OutFile.appendSuffix("E"); actions.push_back(GetAction(cd,InFile,OutFile,PREPROCESSING)); } else { actions.push_back(GetAction(cd,InFile,Output,PREPROCESSING)); } } else { sys::Path TempFile( MakeTempFile(I->first.getBasename(),"E",&ErrMsg)); if (TempFile.isEmpty()) return 1; actions.push_back(GetAction(cd,InFile,TempFile, PREPROCESSING)); InFile = TempFile; } } } else if (finalPhase == PREPROCESSING) { throw cd->langName + " does not support pre-processing"; } else if (action.isSet(REQUIRED_FLAG)) { throw std::string("Don't know how to pre-process ") + cd->langName + " files"; } // Short-circuit remaining actions if all they want is // pre-processing if (finalPhase == PREPROCESSING) { continue; }; /// TRANSLATION PHASE action = cd->Translator; // Get the translation action, if needed, or error if appropriate if (!action.program.isEmpty()) { if (action.isSet(REQUIRED_FLAG) || finalPhase == TRANSLATION) { if (finalPhase == TRANSLATION) { if (Output.isEmpty()) { OutFile.appendSuffix("o"); actions.push_back(GetAction(cd,InFile,OutFile,TRANSLATION)); } else { actions.push_back(GetAction(cd,InFile,Output,TRANSLATION)); } } else { sys::Path TempFile( MakeTempFile(I->first.getBasename(),"trans", &ErrMsg)); if (TempFile.isEmpty()) return 1; actions.push_back(GetAction(cd,InFile,TempFile,TRANSLATION)); InFile = TempFile; } // ll -> bc Helper if (action.isSet(OUTPUT_IS_ASM_FLAG)) { /// The output of the translator is an LLVM Assembly program /// We need to translate it to bytecode Action* action = new Action(); action->program.set("llvm-as"); action->args.push_back(InFile.toString()); action->args.push_back("-o"); InFile.appendSuffix("bc"); action->args.push_back(InFile.toString()); actions.push_back(action); } } } else if (finalPhase == TRANSLATION) { throw cd->langName + " does not support translation"; } else if (action.isSet(REQUIRED_FLAG)) { throw std::string("Don't know how to translate ") + cd->langName + " files"; } // Short-circuit remaining actions if all they want is translation if (finalPhase == TRANSLATION) { continue; } /// OPTIMIZATION PHASE action = cd->Optimizer; // Get the optimization action, if needed, or error if appropriate if (!isSet(EMIT_RAW_FLAG)) { if (!action.program.isEmpty()) { if (action.isSet(REQUIRED_FLAG) || finalPhase == OPTIMIZATION) { if (finalPhase == OPTIMIZATION) { if (Output.isEmpty()) { OutFile.appendSuffix("o"); actions.push_back(GetAction(cd,InFile,OutFile,OPTIMIZATION)); } else { actions.push_back(GetAction(cd,InFile,Output,OPTIMIZATION)); } } else { sys::Path TempFile( MakeTempFile(I->first.getBasename(),"opt", &ErrMsg)); if (TempFile.isEmpty()) return 1; actions.push_back(GetAction(cd,InFile,TempFile,OPTIMIZATION)); InFile = TempFile; } // ll -> bc Helper if (action.isSet(OUTPUT_IS_ASM_FLAG)) { /// The output of the optimizer is an LLVM Assembly program /// We need to translate it to bytecode with llvm-as Action* action = new Action(); action->program.set("llvm-as"); action->args.push_back(InFile.toString()); action->args.push_back("-f"); action->args.push_back("-o"); InFile.appendSuffix("bc"); action->args.push_back(InFile.toString()); actions.push_back(action); } } } else if (finalPhase == OPTIMIZATION) { throw cd->langName + " does not support optimization"; } else if (action.isSet(REQUIRED_FLAG)) { throw std::string("Don't know how to optimize ") + cd->langName + " files"; } } // Short-circuit remaining actions if all they want is optimization if (finalPhase == OPTIMIZATION) { continue; } /// ASSEMBLY PHASE action = cd->Assembler; if (finalPhase == ASSEMBLY) { // Build either a native compilation action or a disassembly action Action* action = new Action(); if (isSet(EMIT_NATIVE_FLAG)) { // Use llc to get the native assembly file action->program.set("llc"); action->args.push_back(InFile.toString()); action->args.push_back("-f"); action->args.push_back("-o"); if (Output.isEmpty()) { OutFile.appendSuffix("o"); action->args.push_back(OutFile.toString()); } else { action->args.push_back(Output.toString()); } actions.push_back(action); } else { // Just convert back to llvm assembly with llvm-dis action->program.set("llvm-dis"); action->args.push_back(InFile.toString()); action->args.push_back("-f"); action->args.push_back("-o"); if (Output.isEmpty()) { OutFile.appendSuffix("ll"); action->args.push_back(OutFile.toString()); } else { action->args.push_back(Output.toString()); } } // Put the action on the list actions.push_back(action); // Short circuit the rest of the loop, we don't want to link continue; } // Register the result of the actions as a link candidate LinkageItems.insert(InFile); } // end while loop over each input file /// RUN THE COMPILATION ACTIONS std::vector::iterator AI = actions.begin(); std::vector::iterator AE = actions.end(); while (AI != AE) { int ActionResult = DoAction(*AI, ErrMsg); if (ActionResult != 0) return ActionResult; AI++; } /// LINKING PHASE if (finalPhase == LINKING) { // Insert the platform-specific system libraries to the path list std::vector SysLibs; sys::Path::GetSystemLibraryPaths(SysLibs); LibraryPaths.insert(LibraryPaths.end(), SysLibs.begin(), SysLibs.end()); // Set up the linking action with llvm-ld Action* link = new Action(); link->program.set("llvm-ld"); // Add in the optimization level requested switch (optLevel) { case OPT_FAST_COMPILE: link->args.push_back("-O1"); break; case OPT_SIMPLE: link->args.push_back("-O2"); break; case OPT_AGGRESSIVE: link->args.push_back("-O3"); break; case OPT_LINK_TIME: link->args.push_back("-O4"); break; case OPT_AGGRESSIVE_LINK_TIME: link->args.push_back("-O5"); break; case OPT_NONE: break; } // Add in all the linkage items we generated. This includes the // output from the translation/optimization phases as well as any // -l arguments specified. for (PathVector::const_iterator I=LinkageItems.begin(), E=LinkageItems.end(); I != E; ++I ) link->args.push_back(I->toString()); // Add in all the libraries we found. for (StringVector::const_iterator I=LibFiles.begin(), E=LibFiles.end(); I != E; ++I ) link->args.push_back(std::string("-l")+*I); // Add in all the library paths to the command line for (PathVector::const_iterator I=LibraryPaths.begin(), E=LibraryPaths.end(); I != E; ++I) link->args.push_back( std::string("-L") + I->toString()); // Add in the additional linker arguments requested for (StringVector::const_iterator I=AdditionalArgs[LINKING].begin(), E=AdditionalArgs[LINKING].end(); I != E; ++I) link->args.push_back( *I ); // Add in other optional flags if (isSet(EMIT_NATIVE_FLAG)) link->args.push_back("-native"); if (isSet(VERBOSE_FLAG)) link->args.push_back("-v"); if (isSet(TIME_PASSES_FLAG)) link->args.push_back("-time-passes"); if (isSet(SHOW_STATS_FLAG)) link->args.push_back("-stats"); if (isSet(STRIP_OUTPUT_FLAG)) link->args.push_back("-s"); if (isSet(DEBUG_FLAG)) { link->args.push_back("-debug"); link->args.push_back("-debug-pass=Details"); } // Add in mandatory flags link->args.push_back("-o"); link->args.push_back(Output.toString()); // Execute the link int ActionResult = DoAction(link, ErrMsg); if (ActionResult != 0) return ActionResult; } } catch (std::string& msg) { cleanup(); throw; } catch (...) { cleanup(); throw std::string("Unspecified error"); } cleanup(); return 0; } /// @} /// @name Data /// @{ private: ConfigDataProvider* cdp; ///< Where we get configuration data from Phases finalPhase; ///< The final phase of compilation OptimizationLevels optLevel; ///< The optimization level to apply unsigned Flags; ///< The driver flags std::string machine; ///< Target machine name PathVector LibraryPaths; ///< -L options PathVector IncludePaths; ///< -I options PathVector ToolPaths; ///< -B options StringVector Defines; ///< -D options sys::PathWithStatus TempDir; ///< Name of the temporary directory. StringTable AdditionalArgs; ///< The -Txyz options StringVector fOptions; ///< -f options StringVector MOptions; ///< -M options StringVector WOptions; ///< -W options /// @} }; } CompilerDriver::~CompilerDriver() { } CompilerDriver::ConfigDataProvider::~ConfigDataProvider() {} CompilerDriver* CompilerDriver::Get(ConfigDataProvider& CDP) { return new CompilerDriverImpl(CDP); } CompilerDriver::ConfigData::ConfigData() : langName() , PreProcessor() , Translator() , Optimizer() , Assembler() , Linker() { StringVector emptyVec; for (unsigned i = 0; i < NUM_PHASES; ++i) opts.push_back(emptyVec); }