diff options
Diffstat (limited to 'tools/llvmc/CompilerDriver.cpp')
-rw-r--r-- | tools/llvmc/CompilerDriver.cpp | 1083 |
1 files changed, 564 insertions, 519 deletions
diff --git a/tools/llvmc/CompilerDriver.cpp b/tools/llvmc/CompilerDriver.cpp index 08d60929a0..7dadf43326 100644 --- a/tools/llvmc/CompilerDriver.cpp +++ b/tools/llvmc/CompilerDriver.cpp @@ -14,26 +14,19 @@ #include "CompilerDriver.h" #include "ConfigLexer.h" -#include "llvm/Bytecode/Reader.h" #include "llvm/Module.h" +#include "llvm/Bytecode/Reader.h" #include "Support/FileUtilities.h" -#include "Support/SystemUtils.h" +#include "Support/SetVector.h" #include "Support/StringExtras.h" #include <iostream> using namespace llvm; namespace { - inline std::string RemoveSuffix(const std::string& fullName) { - size_t dotpos = fullName.rfind('.',fullName.size()); - if ( dotpos == std::string::npos ) return fullName; - return fullName.substr(0, dotpos); - } - - const char OutputSuffix[] = ".o"; void WriteAction(CompilerDriver::Action* action ) { - std::cerr << action->program; + std::cerr << action->program.c_str(); std::vector<std::string>::iterator I = action->args.begin(); while (I != action->args.end()) { std::cerr << " " + *I; @@ -43,7 +36,7 @@ namespace { } void DumpAction(CompilerDriver::Action* action) { - std::cerr << "command = " << action->program; + std::cerr << "command = " << action->program.c_str(); std::vector<std::string>::iterator I = action->args.begin(); while (I != action->args.end()) { std::cerr << " " + *I; @@ -74,558 +67,610 @@ namespace { static const char* DefaultFastCompileOptimizations[] = { "-simplifycfg", "-mem2reg", "-instcombine" }; -} - -// Stuff in this namespace properly belongs in lib/System and needs -// to be portable but we're avoiding that for now. -namespace sys { - - bool FileIsReadable(const std::string& fname) { - return 0 == access(fname.c_str(), F_OK | R_OK); - } - - void CleanupTempFile(const std::string& fname) { - if (FileIsReadable(fname)) - unlink(fname.c_str()); - } - std::string MakeTemporaryDirectory() { - char temp_name[64]; - strcpy(temp_name,"/tmp/llvm_XXXXXX"); - if (0 == mkdtemp(temp_name)) - throw std::string("Can't create temporary directory"); - return temp_name; - } + 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); + } - std::string FindExecutableInPath(const std::string& program) { - // First, just see if the program is already executable - if (isExecutableFile(program)) return program; - - // Get the path. If its empty, we can't do anything - const char *PathStr = getenv("PATH"); - if (PathStr == 0) return ""; - - // Now we have a colon separated list of directories to search; try them. - unsigned PathLen = strlen(PathStr); - while (PathLen) { - // Find the first colon... - const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); - - // Check to see if this first directory contains the executable... - std::string FilePath = std::string(PathStr, Colon) + '/' + program; - if (isExecutableFile(FilePath)) - return FilePath; // Found the executable! - - // Nope it wasn't in this directory, check the next range! - PathLen -= Colon-PathStr; - PathStr = Colon; - - // Advance past duplicate coons - while (*PathStr == ':') { - PathStr++; - PathLen--; + virtual ~CompilerDriverImpl() { + cleanup(); + cdp = 0; + LibraryPaths.clear(); + AdditionalArgs.clear(); } - } - // If we fell out, we ran out of directories in PATH to search, return failure - return ""; - } -} + /// @} + /// @name Methods + /// @{ + public: + virtual void setFinalPhase( Phases phase ) { + finalPhase = phase; + } -CompilerDriver::CompilerDriver(ConfigDataProvider& confDatProv ) - : cdp(&confDatProv) - , finalPhase(LINKING) - , optLevel(OPT_FAST_COMPILE) - , isDryRun(false) - , isVerbose(false) - , isDebug(false) - , timeActions(false) - , emitRawCode(false) - , emitNativeCode(false) - , keepTemps(false) - , machine() - , LibraryPaths() - , AdditionalArgs() - , TempDir() -{ - // FIXME: These libraries are platform specific - LibraryPaths.push_back("/lib"); - LibraryPaths.push_back("/usr/lib"); - AdditionalArgs.reserve(NUM_PHASES); - StringVector emptyVec; - for (unsigned i = 0; i < NUM_PHASES; ++i) - AdditionalArgs.push_back(emptyVec); -} + virtual void setOptimization( OptimizationLevels level ) { + optLevel = level; + } -CompilerDriver::~CompilerDriver() { - cdp = 0; - LibraryPaths.clear(); - AdditionalArgs.clear(); -} + virtual void setDriverFlags( unsigned flags ) { + Flags = flags & DRIVER_FLAGS_MASK; + } -CompilerDriver::ConfigData::ConfigData() - : langName() - , PreProcessor() - , Translator() - , Optimizer() - , Assembler() - , Linker() -{ - StringVector emptyVec; - for (unsigned i = 0; i < NUM_PHASES; ++i) - opts.push_back(emptyVec); -} + virtual void setOutputMachine( const std::string& machineName ) { + machine = machineName; + } -void CompilerDriver::error( const std::string& errmsg ) { - std::cerr << "llvmc: Error: " << errmsg << ".\n"; - exit(1); -} + virtual void setPhaseArgs(Phases phase, const StringVector& opts) { + assert(phase <= LINKING && phase >= PREPROCESSING); + AdditionalArgs[phase] = opts; + } -CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd, - const std::string& input, - const std::string& 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] == '%') { - if (*PI == "%in%") { - action->args.push_back(input); - } else if (*PI == "%out%") { - action->args.push_back(output); - } else if (*PI == "%time%") { - if (timePasses) - action->args.push_back("-time-passes"); - } else if (*PI == "%stats%") { - if (showStats) - action->args.push_back("-stats"); - } else if (*PI == "%target%") { - // FIXME: Ignore for now - } else if (*PI == "%opt%") { - if (!emitRawCode) { - 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 - error("Optimization options for level " + utostr(unsigned(optLevel)) + - " were not specified"); + 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; } - } else 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 { - error("Invalid substitution name" + *PI); } - } else { - // Its not a substitution, just put it in the action - action->args.push_back(*PI); - } - PI++; - } + virtual void addLibraryPath( const sys::Path& libPath ) { + LibraryPaths.push_back(libPath); + } - // Finally, we're done - return action; -} - -bool CompilerDriver::DoAction(Action*action) { - assert(action != 0 && "Invalid Action!"); - if (isVerbose) - WriteAction(action); - if (!isDryRun) { - std::string prog(sys::FindExecutableInPath(action->program)); - if (prog.empty()) - error("Can't find program '" + action->program + "'"); - - // Get the program's arguments - const char* argv[action->args.size() + 1]; - argv[0] = prog.c_str(); - unsigned i = 1; - for (; i <= action->args.size(); ++i) - argv[i] = action->args[i-1].c_str(); - argv[i] = 0; - - // Invoke the program - return !ExecWait(argv, environ); - } - 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. -std::string CompilerDriver::GetPathForLinkageItem(const std::string& link_item, - const std::string& dir) { - std::string fullpath(dir + "/" + link_item + ".o"); - if (::sys::FileIsReadable(fullpath)) - return fullpath; - fullpath = dir + "/" + link_item + ".bc"; - if (::sys::FileIsReadable(fullpath)) - return fullpath; - fullpath = dir + "/lib" + link_item + ".a"; - if (::sys::FileIsReadable(fullpath)) - return fullpath; - fullpath = dir + "/lib" + link_item + ".so"; - if (::sys::FileIsReadable(fullpath)) - return fullpath; - return ""; -} + /// @} + /// @name Functions + /// @{ + private: + bool isSet(DriverFlags flag) { + return 0 != ((flag & DRIVER_FLAGS_MASK) & Flags); + } -/// 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 CompilerDriver::ProcessLinkageItem(const std::string& link_item, - SetVector<std::string>& 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. - std::string fullpath; - if (!sys::FileIsReadable(link_item)) { - // First, look for the library using the -L arguments specified - // on the command line. - StringVector::iterator PI = LibraryPaths.begin(); - StringVector::iterator PE = LibraryPaths.end(); - while (PI != PE && fullpath.empty()) { - fullpath = GetPathForLinkageItem(link_item,*PI); - ++PI; - } + 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"; + } + } - // 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.empty()) { - err = std::string("Can't find linkage item '") + link_item + "'"; - return false; - } - } else { - fullpath = link_item; - } + 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; + } - // 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, "llvm")) { - // Process the dependent libraries recursively - Module::LibraryListType modlibs; - if (GetBytecodeDependentLibraries(fullpath,modlibs)) { - // Traverse the dependent libraries list - Module::lib_iterator LI = modlibs.begin(); - Module::lib_iterator LE = modlibs.end(); - while ( LI != LE ) { - if (!ProcessLinkageItem(*LI,set,err)) { - if (err.empty()) { - err = std::string("Library '") + *LI + - "' is not valid for linking but is required by file '" + - fullpath + "'"; + 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] == '%') { + if (*PI == "%in%") { + action->args.push_back(input.get()); + } else if (*PI == "%out%") { + action->args.push_back(output.get()); + } else if (*PI == "%time%") { + if (isSet(TIME_PASSES_FLAG)) + action->args.push_back("-time-passes"); + } else if (*PI == "%stats%") { + if (isSet(SHOW_STATS_FLAG)) + action->args.push_back("-stats"); + } else if (*PI == "%force%") { + if (isSet(FORCE_FLAG)) + action->args.push_back("-f"); + } else if (*PI == "%verbose%") { + if (isSet(VERBOSE_FLAG)) + action->args.push_back("-v"); + } else if (*PI == "%target%") { + // FIXME: Ignore for now + } 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 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 { + throw "Invalid substitution name" + *PI; + } } else { - err += " which is required by file '" + fullpath + "'"; + // Its not a substitution, just put it in the action + action->args.push_back(*PI); } - return false; + PI++; } - ++LI; - } - } else if (err.empty()) { - err = std::string("The dependent libraries could not be extracted from '") - + fullpath; - return false; - } - } - return true; -} -int CompilerDriver::execute(const InputList& InpList, - const std::string& Output ) { - // Echo the configuration of options if we're running verbose - if (isDebug) - { - std::cerr << "Compiler Driver Options:\n"; - std::cerr << "DryRun = " << isDryRun << "\n"; - std::cerr << "Verbose = " << isVerbose << " \n"; - std::cerr << "TimeActions = " << timeActions << "\n"; - std::cerr << "EmitRawCode = " << emitRawCode << "\n"; - std::cerr << "OutputMachine = " << machine << "\n"; - std::cerr << "EmitNativeCode = " << emitNativeCode << "\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()) - error("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.empty()) - error("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; - - // Create a temporary directory for our temporary files - std::string TempDir(sys::MakeTemporaryDirectory()); - std::string TempPreprocessorOut(TempDir + "/preproc.o"); - std::string TempTranslatorOut(TempDir + "/trans.o"); - std::string TempOptimizerOut(TempDir + "/opt.o"); - std::string TempAssemblerOut(TempDir + "/asm.o"); - - /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases - // for each input item - std::vector<std::string> LinkageItems; - std::string 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) { - error("Pre-compiled objects found but linking not requested"); + // Finally, we're done + return action; } - LinkageItems.push_back(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) - error(std::string("Files of type '") + I->second + - "' are not recognized." ); - if (isDebug) - DumpConfigData(cd,I->second); - - // Initialize the input file - std::string InFile(I->first); - - // PRE-PROCESSING PHASE - Action& action = cd->PreProcessor; - - // Get the preprocessing action, if needed, or error if appropriate - if (!action.program.empty()) { - if (action.isSet(REQUIRED_FLAG) || finalPhase == PREPROCESSING) { - if (finalPhase == PREPROCESSING) - actions.push_back(GetAction(cd,InFile,OutFile,PREPROCESSING)); - else { - actions.push_back(GetAction(cd,InFile,TempPreprocessorOut, - PREPROCESSING)); - InFile = TempPreprocessorOut; + 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 "Can't find program '" + action->program.get() + "'"; + + // Invoke the program + return 0 == action->program.ExecuteAndWait(action->args); } + return true; } - } else if (finalPhase == PREPROCESSING) { - error(cd->langName + " does not support pre-processing"); - } else if (action.isSet(REQUIRED_FLAG)) { - error(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; }; + /// 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; + } - /// TRANSLATION PHASE - action = cd->Translator; + /// 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; + } - // Get the translation action, if needed, or error if appropriate - if (!action.program.empty()) { - if (action.isSet(REQUIRED_FLAG) || finalPhase == TRANSLATION) { - if (finalPhase == TRANSLATION) - actions.push_back(GetAction(cd,InFile,OutFile,TRANSLATION)); - else { - actions.push_back(GetAction(cd,InFile,TempTranslatorOut,TRANSLATION)); - InFile = TempTranslatorOut; + // 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; } - // 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 = "llvm-as"; - action->args.push_back(InFile); - action->args.push_back("-o"); - InFile += ".bc"; - action->args.push_back(InFile); - actions.push_back(action); + // 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; } - } else if (finalPhase == TRANSLATION) { - error(cd->langName + " does not support translation"); - } else if (action.isSet(REQUIRED_FLAG)) { - error(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 (!emitRawCode) { - if (!action.program.empty()) { - if (action.isSet(REQUIRED_FLAG) || finalPhase == OPTIMIZATION) { - if (finalPhase == OPTIMIZATION) - actions.push_back(GetAction(cd,InFile,OutFile,OPTIMIZATION)); - else { - actions.push_back(GetAction(cd,InFile,TempOptimizerOut,OPTIMIZATION)); - InFile = TempOptimizerOut; + /// @} + /// @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"; } - // 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 = "llvm-as"; - action->args.push_back(InFile); - action->args.push_back("-f"); - action->args.push_back("-o"); - InFile += ".bc"; - action->args.push_back(InFile); - actions.push_back(action); + + // 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"; |