| //===- 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/Bytecode/Reader.h" |
| #include "llvm/System/Signals.h" |
| #include "llvm/Support/FileUtilities.h" |
| #include "llvm/ADT/SetVector.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include <iostream> |
| |
| using namespace llvm; |
| |
| namespace { |
| |
| void WriteAction(CompilerDriver::Action* action ) { |
| std::cerr << action->program.c_str(); |
| std::vector<std::string>::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<std::string>::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); |
| } |
| |
| /// This specifies the passes to run for OPT_FAST_COMPILE (-O1) |
| /// which should reduce the volume of code and make compilation |
| /// faster. This is also safe on any llvm module. |
| static const char* DefaultFastCompileOptimizations[] = { |
| "-simplifycfg", "-mem2reg", "-instcombine" |
| }; |
| |
| class CompilerDriverImpl : public CompilerDriver { |
| /// @name Constructors |
| /// @{ |
| public: |
| CompilerDriverImpl(ConfigDataProvider& confDatProv ) |
| : cdp(&confDatProv) |
| , finalPhase(LINKING) |
| , optLevel(OPT_FAST_COMPILE) |
| , Flags(0) |
| , machine() |
| , LibraryPaths() |
| , TempDir() |
| , AdditionalArgs() |
| { |
| TempDir = sys::Path::GetTemporaryDirectory(); |
| sys::RemoveDirectoryOnSignal(TempDir); |
| 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(); |
| AdditionalArgs.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_directory(*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_directory(*I); |
| LibraryPaths.push_back(tmp); |
| ++I; |
| } |
| } |
| |
| virtual void addLibraryPath( const sys::Path& libPath ) { |
| LibraryPaths.push_back(libPath); |
| } |
| |
| /// @} |
| /// @name Functions |
| /// @{ |
| private: |
| bool isSet(DriverFlags flag) { |
| return 0 != ((flag & DRIVER_FLAGS_MASK) & Flags); |
| } |
| |
| void cleanup() { |
| if (!isSet(KEEP_TEMPS_FLAG)) { |
| if (TempDir.is_directory() && TempDir.writable()) |
| TempDir.destroy_directory(/*remove_contents=*/true); |
| } else { |
| std::cout << "Temporary files are in " << TempDir.get() << "\n"; |
| } |
| } |
| |
| sys::Path MakeTempFile(const std::string& basename, const std::string& suffix ) { |
| sys::Path result(TempDir); |
| if (!result.append_file(basename)) |
| throw basename + ": can't use this file name"; |
| if (!result.append_suffix(suffix)) |
| throw suffix + ": can't use this file suffix"; |
| 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->program = pat->program; |
| action->flags = pat->flags; |
| |
| // 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 '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 == "%force%") { |
| if (isSet(FORCE_FLAG)) |
| action->args.push_back("-f"); |
| } else |
| found = false; |
| break; |
| case 'i': |
| if (*PI == "%in%") { |
| action->args.push_back(input.get()); |
| } 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->get() ); |
| ++I; |
| } |
| } else |
| found = false; |
| break; |
| case 'l': |
| if (*PI == "%libs%") { |
| PathVector::iterator I = LibraryPaths.begin(); |
| PathVector::iterator E = LibraryPaths.end(); |
| while (I != E) { |
| action->args.push_back( std::string("-L") + I->get() ); |
| ++I; |
| } |
| } else |
| found = false; |
| break; |
| case 'o': |
| if (*PI == "%out%") { |
| action->args.push_back(output.get()); |
| } else if (*PI == "%opt%") { |
| if (!isSet(EMIT_RAW_FLAG)) { |
| if (cd->opts.size() > static_cast<unsigned>(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; |
| 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.get() + "'"; |
| } else { |
| // It's not a legal substitution, just pass it through |
| action->args.push_back(*PI); |
| } |
| } |
| } else { |
| // Its not a substitution, just put it in the action |
| action->args.push_back(*PI); |
| } |
| PI++; |
| } |
| |
| // Finally, we're done |
| return action; |
| } |
| |
| bool DoAction(Action*action) { |
| assert(action != 0 && "Invalid Action!"); |
| if (isSet(VERBOSE_FLAG)) |
| WriteAction(action); |
| if (!isSet(DRY_RUN_FLAG)) { |
| action->program = sys::Program::FindProgramByName(action->program.get()); |
| if (action->program.is_empty()) |
| throw std::string("Can't find program '") + action->program.get() + "'"; |
| |
| // Invoke the program |
| return 0 == action->program.ExecuteAndWait(action->args); |
| } |
| return true; |
| } |
| |
| /// 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 directory specified. |
| llvm::sys::Path GetPathForLinkageItem(const std::string& link_item, |
| const sys::Path& dir) { |
| sys::Path fullpath(dir); |
| fullpath.append_file(link_item); |
| fullpath.append_suffix("bc"); |
| if (fullpath.readable()) |
| return fullpath; |
| fullpath.elide_suffix(); |
| fullpath.append_suffix("o"); |
| if (fullpath.readable()) |
| return fullpath; |
| fullpath = dir; |
| fullpath.append_file(std::string("lib") + link_item); |
| fullpath.append_suffix("a"); |
| if (fullpath.readable()) |
| return fullpath; |
| fullpath.elide_suffix(); |
| fullpath.append_suffix("so"); |
| if (fullpath.readable()) |
| 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<sys::Path>& 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.readable()) { |
| // First, look for the library using the -L arguments specified |
| // on the command line. |
| PathVector::iterator PI = LibraryPaths.begin(); |
| PathVector::iterator PE = LibraryPaths.end(); |
| while (PI != PE && fullpath.is_empty()) { |
| fullpath = GetPathForLinkageItem(link_item.get(),*PI); |
| ++PI; |
| } |
| |
| // If we didn't find the file in any of the library search paths |
| // so we have to bail. No where else to look. |
| if (fullpath.is_empty()) { |
| err = std::string("Can't find linkage item '") + link_item.get() + "'"; |
| 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 (CheckMagic(fullpath.get(), "llvm")) { |
| // Process the dependent libraries recursively |
| Module::LibraryListType modlibs; |
| if (GetBytecodeDependentLibraries(fullpath.get(),modlibs)) { |
| // 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.get() + "'"; |
| } else { |
| err += " which is required by file '" + fullpath.get() + "'"; |
| } |
| return false; |
| } |
| ++LI; |
| } |
| } else if (err.empty()) { |
| err = std::string("The dependent libraries could not be extracted from '") |
| + fullpath.get(); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /// @} |
| /// @name Methods |
| /// @{ |
| public: |
| virtual int execute(const InputList& InpList, const sys::Path& Output ) { |
| 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 << "ForceOutput = " << isSet(FORCE_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.get() << "(" << I->second << ")\n"; |
| ++I; |
| } |
| std::cerr << "Output: " << Output.get() << "\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.is_empty()) |
| throw std::string( |
| "An output file name must be specified for linker output"); |
| |
| // This vector holds all the resulting actions of the following loop. |
| std::vector<Action*> actions; |
| |
| /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases |
| // for each input item |
| SetVector<sys::Path> LinkageItems; |
| sys::Path OutFile(Output); |
| InputList::const_iterator I = InpList.begin(); |
| while ( I != InpList.end() ) { |
| // 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") { |
| // 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"); |
| } |
| LinkageItems.insert(I->first); |
| ++I; 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); |
| |
| // Initialize the input file |
| sys::Path InFile(I->first); |
| |
| // PRE-PROCESSING PHASE |
| Action& action = cd->PreProcessor; |
| |
| // Get the preprocessing action, if needed, or error if appropriate |
| if (!action.program.is_empty()) { |
| if (action.isSet(REQUIRED_FLAG) || finalPhase == PREPROCESSING) { |
| if (finalPhase == PREPROCESSING) |
| actions.push_back(GetAction(cd,InFile,OutFile,PREPROCESSING)); |
| else { |
| sys::Path TempFile(MakeTempFile(I->first.get(),"E")); |
| 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) { ++I; continue; }; |
| |
| /// TRANSLATION PHASE |
| action = cd->Translator; |
| |
| // Get the translation action, if needed, or error if appropriate |
| if (!action.program.is_empty()) { |
| if (action.isSet(REQUIRED_FLAG) || finalPhase == TRANSLATION) { |
| if (finalPhase == TRANSLATION) |
| actions.push_back(GetAction(cd,InFile,OutFile,TRANSLATION)); |
| else { |
| sys::Path TempFile(MakeTempFile(I->first.get(),"trans")); |
| 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_file("llvm-as"); |
| action->args.push_back(InFile.get()); |
| action->args.push_back("-o"); |
| InFile.append_suffix("bc"); |
| action->args.push_back(InFile.get()); |
| 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) { ++I; continue; } |
| |
| /// OPTIMIZATION PHASE |
| action = cd->Optimizer; |
| |
| // Get the optimization action, if needed, or error if appropriate |
| if (!isSet(EMIT_RAW_FLAG)) { |
| if (!action.program.is_empty()) { |
| if (action.isSet(REQUIRED_FLAG) || finalPhase == OPTIMIZATION) { |
| if (finalPhase == OPTIMIZATION) |
| actions.push_back(GetAction(cd,InFile,OutFile,OPTIMIZATION)); |
| else { |
| sys::Path TempFile(MakeTempFile(I->first.get(),"opt")); |
| actions.push_back(GetAction(cd,InFile,TempFile,OPTIMIZATION)); |
| 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_file("llvm-as"); |
| action->args.push_back(InFile.get()); |
| action->args.push_back("-f"); |
| action->args.push_back("-o"); |
| InFile.append_suffix("bc"); |
| action->args.push_back(InFile.get()); |
| 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) { ++I; continue; } |
| |
| /// ASSEMBLY PHASE |
| action = cd->Assembler; |
| |
| if (finalPhase == ASSEMBLY || isSet(EMIT_NATIVE_FLAG)) { |
| if (isSet(EMIT_NATIVE_FLAG)) { |
| if (action.program.is_empty()) { |
| throw std::string("Native Assembler not specified for ") + |
| cd->langName + " files"; |
| } else if (finalPhase == ASSEMBLY) { |
| actions.push_back(GetAction(cd,InFile,OutFile,ASSEMBLY)); |
| } else { |
| sys::Path TempFile(MakeTempFile(I->first.get(),"S")); |
| actions.push_back(GetAction(cd,InFile,TempFile,ASSEMBLY)); |
| InFile = TempFile; |
| } |
| } else { |
| // Just convert back to llvm assembly with llvm-dis |
| Action* action = new Action(); |
| action->program.set_file("llvm-dis"); |
| action->args.push_back(InFile.get()); |
| action->args.push_back("-f"); |
| action->args.push_back("-o"); |
| action->args.push_back(OutFile.get()); |
| actions.push_back(action); |
| } |
| } |
| |
| // Short-circuit remaining actions if all they want is assembly output |
| if (finalPhase == ASSEMBLY) { ++I; continue; } |
| |
| // Register the OutFile as a link candidate |
| LinkageItems.insert(InFile); |
| |
| // Go to next file to be processed |
| ++I; |
| } |
| |
| /// RUN THE COMPILATION ACTIONS |
| std::vector<Action*>::iterator AI = actions.begin(); |
| std::vector<Action*>::iterator AE = actions.end(); |
| while (AI != AE) { |
| if (!DoAction(*AI)) |
| throw std::string("Action failed"); |
| AI++; |
| } |
| |
| /// LINKING PHASE |
| actions.clear(); |
| if (finalPhase == LINKING) { |
| if (isSet(EMIT_NATIVE_FLAG)) { |
| throw std::string( |
| "llvmc doesn't know how to link native code yet"); |
| } else { |
| // First, we need to examine the files to ensure that they all contain |
| // bytecode files. Since the final output is bytecode, we can only |
| // link bytecode. |
| SetVector<sys::Path>::const_iterator I = LinkageItems.begin(); |
| SetVector<sys::Path>::const_iterator E = LinkageItems.end(); |
| std::string errmsg; |
| |
| while (I != E && ProcessLinkageItem(*I,LinkageItems,errmsg)) |
| ++I; |
| |
| if (!errmsg.empty()) |
| throw errmsg; |
| |
| // Insert the system libraries. |
| LibraryPaths.push_back(sys::Path::GetSystemLibraryPath1()); |
| LibraryPaths.push_back(sys::Path::GetSystemLibraryPath2()); |
| |
| // We're emitting bytecode so let's build an llvm-link Action |
| Action* link = new Action(); |
| link->program.set_file("llvm-link"); |
| for (PathVector::const_iterator I=LinkageItems.begin(), |
| E=LinkageItems.end(); I != E; ++I ) |
| link->args.push_back(I->get()); |
| if (isSet(VERBOSE_FLAG)) |
| link->args.push_back("-v"); |
| link->args.push_back("-f"); |
| link->args.push_back("-o"); |
| link->args.push_back(OutFile.get()); |
| if (isSet(TIME_PASSES_FLAG)) |
| link->args.push_back("-time-passes"); |
| if (isSet(SHOW_STATS_FLAG)) |
| link->args.push_back("-stats"); |
| actions.push_back(link); |
| } |
| } |
| |
| /// RUN THE LINKING ACTIONS |
| AI = actions.begin(); |
| AE = actions.end(); |
| while (AI != AE) { |
| if (!DoAction(*AI)) |
| throw std::string("Action failed"); |
| AI++; |
| } |
| } 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 |
| StringVector Defines; ///< -D options |
| sys::Path TempDir; ///< Name of the temporary directory. |
| StringTable AdditionalArgs; ///< The -Txyz options |
| |
| /// @} |
| }; |
| } |
| |
| CompilerDriver::~CompilerDriver() { |
| } |
| |
| 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); |
| } |
| |
| // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab |