#include "ConfigLexer.h"
#include "llvm/Module.h"
#include "llvm/Bytecode/Reader.h"
+#include "llvm/Support/Timer.h"
#include "llvm/System/Signals.h"
-#include "llvm/Support/FileUtilities.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include <iostream>
LibraryPaths.push_back(libPath);
}
+ 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
/// @{
if (*PI == "%force%") {
if (isSet(FORCE_FLAG))
action->args.push_back("-f");
+ } else if (*PI == "%fOpts%") {
+ action->args.insert(action->args.end(), fOptions.begin(),
+ fOptions.end());
} else
found = false;
break;
} else
found = false;
break;
+ case 'M':
+ if (*PI == "%Mopts") {
+ action->args.insert(action->args.end(), MOptions.begin(),
+ MOptions.end());
+ } else
+ found = false;
+ break;
+ case 'W':
+ if (*PI == "%Wopts") {
+ action->args.insert(action->args.end(), WOptions.begin(),
+ WOptions.end());
+ } else
+ found = false;
+ break;
default:
found = false;
break;
throw std::string("Can't find program '") + action->program.get() + "'";
// Invoke the program
- return 0 == action->program.ExecuteAndWait(action->args);
+ if (isSet(TIME_ACTIONS_FLAG)) {
+ Timer timer(action->program.get());
+ timer.startTimer();
+ int resultCode = sys::Program::ExecuteAndWait(action->program,action->args);
+ timer.stopTimer();
+ timer.print(timer,std::cerr);
+ return resultCode == 0;
+ }
+ else
+ return 0 == sys::Program::ExecuteAndWait(action->program, action->args);
}
return true;
}
/// 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) {
+ const sys::Path& dir,
+ bool native = false) {
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;
+ if (native) {
+ fullpath.append_suffix("a");
+ } else {
+ 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();
set.insert(fullpath);
// If its an LLVM bytecode file ...
- if (CheckMagic(fullpath.get(), "llvm")) {
+ if (fullpath.is_bytecode_file()) {
// Process the dependent libraries recursively
Module::LibraryListType modlibs;
if (GetBytecodeDependentLibraries(fullpath.get(),modlibs)) {
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.is_empty() &&
+ 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<Action*> actions;
/// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases
// for each input item
SetVector<sys::Path> LinkageItems;
+ std::vector<std::string> LibFiles;
sys::Path OutFile(Output);
InputList::const_iterator I = InpList.begin();
while ( I != InpList.end() ) {
// 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") {
+ 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");
}
- LinkageItems.insert(I->first);
+ if (ftype.empty())
+ LibFiles.push_back(I->first.get());
+ else
+ LinkageItems.insert(I->first);
++I; continue; // short circuit remainder of loop
}
// 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)
+ if (finalPhase == PREPROCESSING) {
+ if (OutFile.is_empty()) {
+ OutFile = I->first;
+ OutFile.append_suffix("E");
+ }
actions.push_back(GetAction(cd,InFile,OutFile,PREPROCESSING));
- else {
+ } else {
sys::Path TempFile(MakeTempFile(I->first.get(),"E"));
actions.push_back(GetAction(cd,InFile,TempFile,PREPROCESSING));
InFile = TempFile;
// 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)
+ if (finalPhase == TRANSLATION) {
+ if (OutFile.is_empty()) {
+ OutFile = I->first;
+ OutFile.append_suffix("o");
+ }
actions.push_back(GetAction(cd,InFile,OutFile,TRANSLATION));
- else {
+ } else {
sys::Path TempFile(MakeTempFile(I->first.get(),"trans"));
actions.push_back(GetAction(cd,InFile,TempFile,TRANSLATION));
InFile = TempFile;
if (!isSet(EMIT_RAW_FLAG)) {
if (!action.program.is_empty()) {
if (action.isSet(REQUIRED_FLAG) || finalPhase == OPTIMIZATION) {
- if (finalPhase == OPTIMIZATION)
+ if (finalPhase == OPTIMIZATION) {
+ if (OutFile.is_empty()) {
+ OutFile = I->first;
+ OutFile.append_suffix("o");
+ }
actions.push_back(GetAction(cd,InFile,OutFile,OPTIMIZATION));
- else {
+ } 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
+ /// 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_file("llvm-as");
action->args.push_back(InFile.get());
/// ASSEMBLY PHASE
action = cd->Assembler;
- if (finalPhase == ASSEMBLY || isSet(EMIT_NATIVE_FLAG)) {
+ if (finalPhase == ASSEMBLY) {
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;
+ // Use llc to get the native assembly file
+ Action* action = new Action();
+ action->program.set_file("llc");
+ action->args.push_back(InFile.get());
+ action->args.push_back("-f");
+ action->args.push_back("-o");
+ if (OutFile.is_empty()) {
+ OutFile = I->first;
+ OutFile.append_suffix("s");
}
+ action->args.push_back(OutFile.get());
} else {
// Just convert back to llvm assembly with llvm-dis
Action* action = new Action();
action->args.push_back(OutFile.get());
actions.push_back(action);
}
+
+ // Short circuit the rest of the loop, we don't want to link
+ ++I;
+ continue;
}
- // Short-circuit remaining actions if all they want is assembly output
- if (finalPhase == ASSEMBLY) { ++I; continue; }
-
- // Register the OutFile as a link candidate
+ // Register the result of the actions as a link candidate
LinkageItems.insert(InFile);
// Go to next file to be processed
++I;
- }
+ } // end while loop over each input file
/// RUN THE COMPILATION ACTIONS
std::vector<Action*>::iterator AI = actions.begin();
}
/// 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);
+ // Insert the platform-specific system libraries to the path list
+ LibraryPaths.push_back(sys::Path::GetSystemLibraryPath1());
+ LibraryPaths.push_back(sys::Path::GetSystemLibraryPath2());
+
+ // We're emitting native code so let's build an gccld Action
+ Action* link = new Action();
+ link->program.set_file("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;
}
- }
- /// RUN THE LINKING ACTIONS
- AI = actions.begin();
- AE = actions.end();
- while (AI != AE) {
- if (!DoAction(*AI))
- throw std::string("Action failed");
- AI++;
+ // 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->get());
+
+ // Add in all the libraries we found.
+ for (std::vector<std::string>::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->get());
+
+ // 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(OutFile.get());
+
+ // Execute the link
+ if (!DoAction(link))
+ throw std::string("Action failed");
}
} catch (std::string& msg) {
cleanup();
StringVector Defines; ///< -D options
sys::Path TempDir; ///< Name of the temporary directory.
StringTable AdditionalArgs; ///< The -Txyz options
+ StringVector fOptions; ///< -f options
+ StringVector MOptions; ///< -M options
+ StringVector WOptions; ///< -W options
/// @}
};
FLAGS_MASK = 0x000F, ///< Union of all flags
};
- /// @brief Driver specific flags
- enum DriverFlags {
- DRY_RUN_FLAG = 0x0001, ///< Do everything but execute actions
- FORCE_FLAG = 0x0002, ///< Force overwrite of output files
- VERBOSE_FLAG = 0x0004, ///< Print each action
- DEBUG_FLAG = 0x0008, ///< Print debug information
- TIME_PASSES_FLAG = 0x0010, ///< Time the passes as they execute
- TIME_ACTIONS_FLAG = 0x0020, ///< Time the actions as they execute
- SHOW_STATS_FLAG = 0x0040, ///< Show pass statistics
- EMIT_NATIVE_FLAG = 0x0080, ///< Emit native code instead of bc
- EMIT_RAW_FLAG = 0x0100, ///< Emit raw, unoptimized bytecode
- KEEP_TEMPS_FLAG = 0x0200, ///< Don't delete temporary files
- DRIVER_FLAGS_MASK = 0x02FF, ///< Union of the above flags
- };
-
/// This type is the input list to the CompilerDriver. It provides
/// a vector of pathname/filetype pairs. The filetype is used to look up
/// the configuration of the actions to be taken by the driver.
/// language.
struct Action {
Action() : flags(0) {}
- sys::Program program; ///< The program to execve
+ sys::Path program; ///< The program to execve
StringVector args; ///< Arguments to the program
unsigned flags; ///< Action specific flags
void set(unsigned fl ) { flags |= fl; }
virtual void setConfigDir(const sys::Path& dirName) = 0;
};
+ /// These flags control various actions of the compiler driver. They are
+ /// used by adding the needed flag values together and passing them to the
+ /// compiler driver's setDriverFlags method.
+ /// @see setDriverFlags
+ /// @brief Driver specific flags
+ enum DriverFlags {
+ DRY_RUN_FLAG = 0x0001, ///< Do everything but execute actions
+ FORCE_FLAG = 0x0002, ///< Force overwrite of output files
+ VERBOSE_FLAG = 0x0004, ///< Print each action
+ DEBUG_FLAG = 0x0008, ///< Print debug information
+ TIME_PASSES_FLAG = 0x0010, ///< Time the passes as they execute
+ TIME_ACTIONS_FLAG = 0x0020, ///< Time the actions as they execute
+ SHOW_STATS_FLAG = 0x0040, ///< Show pass statistics
+ EMIT_NATIVE_FLAG = 0x0080, ///< Emit native code instead of bc
+ EMIT_RAW_FLAG = 0x0100, ///< Emit raw, unoptimized bytecode
+ KEEP_TEMPS_FLAG = 0x0200, ///< Don't delete temporary files
+ STRIP_OUTPUT_FLAG = 0x0400, ///< Strip symbols from linked output
+ DRIVER_FLAGS_MASK = 0x07FF, ///< Union of the above flags
+ };
+
/// @}
/// @name Constructors
/// @{
/// libraries.
virtual void addLibraryPath( const sys::Path& libPath ) = 0;
+ /// @brief Set the list of -f options to be passed through
+ virtual void setfPassThrough(const StringVector& fOpts) = 0;
+
+ /// @brief Set the list of -M options to be passed through
+ virtual void setMPassThrough(const StringVector& fOpts) = 0;
+
+ /// @brief Set the list of -W options to be passed through
+ virtual void setWPassThrough(const StringVector& fOpts) = 0;
+
/// @}
};
}
cl::desc("Pass specific options to the linker"),
cl::value_desc("option"));
+cl::list<std::string> fOpts("f", cl::ZeroOrMore, cl::Prefix,
+ cl::desc("Pass through -f options to compiler tools"),
+ cl::value_desc("optimization option"));
+
+cl::list<std::string> MOpts("M", cl::ZeroOrMore, cl::Prefix,
+ cl::desc("Pass through -M options to compiler tools"),
+ cl::value_desc("dependency option"));
+
+cl::list<std::string> WOpts("W", cl::ZeroOrMore, cl::Prefix,
+ cl::desc("Pass through -W options to compiler tools"),
+ cl::value_desc("warnings category"));
+
//===------------------------------------------------------------------------===
//=== INPUT OPTIONS
//===------------------------------------------------------------------------===
cl::opt<std::string> OutputFilename("o",
cl::desc("Override output filename"), cl::value_desc("filename"));
-cl::opt<bool> ForceOutput("f", cl::Optional, cl::init(false),
+cl::opt<bool> ForceOutput("F", cl::Optional, cl::init(false),
cl::desc("Force output files to be overridden"));
cl::opt<std::string> OutputMachine("m", cl::Prefix,
cl::opt<bool> DebugOutput("g", cl::init(false),
cl::desc("Generate objects that include debug symbols"));
+cl::opt<bool> StripOutput("strip", cl::init(false),
+ cl::desc("Strip all symbols from linked output file"));
+
//===------------------------------------------------------------------------===
//=== INFORMATION OPTIONS
//===------------------------------------------------------------------------===
cl::opt<bool> ShowStats("stats", cl::Optional, cl::init(false),
cl::desc("Print statistics accumulated during optimization"));
-cl::list<std::string> Warnings("W", cl::Prefix,
- cl::desc("Provide warnings for additional classes of errors"),
- cl::value_desc("warning category"));
-
//===------------------------------------------------------------------------===
//=== ADVANCED OPTIONS
//===------------------------------------------------------------------------===
if (ShowStats) flags |= CompilerDriver::SHOW_STATS_FLAG;
if (TimeActions) flags |= CompilerDriver::TIME_ACTIONS_FLAG;
if (TimePassesIsEnabled) flags |= CompilerDriver::TIME_PASSES_FLAG;
+ if (StripOutput) flags |= CompilerDriver::STRIP_OUTPUT_FLAG;
CD->setDriverFlags(flags);
// Specify requred parameters
CD->setIncludePaths(Includes);
CD->setSymbolDefines(Defines);
CD->setLibraryPaths(LibPaths);
+ CD->setfPassThrough(fOpts);
+ CD->setMPassThrough(MOpts);
+ CD->setWPassThrough(WOpts);
// Provide additional tool arguments
if (!PreprocessorToolOpts.empty())