diff --git a/tools/llvmc2/Action.cpp b/tools/llvmc2/Action.cpp index 3d61d37368f..80531c0806a 100644 --- a/tools/llvmc2/Action.cpp +++ b/tools/llvmc2/Action.cpp @@ -34,7 +34,7 @@ namespace { if (!prog.canExecute()) throw std::runtime_error("Program '" + name + "' is not executable."); - // Build the command line vector and redirects. + // Build the command line vector and the redirects array. const sys::Path* redirects[3] = {0,0,0}; sys::Path stdout_redirect; diff --git a/tools/llvmc2/CompilationGraph.cpp b/tools/llvmc2/CompilationGraph.cpp index ed03f5856ec..4b04d6f60b3 100644 --- a/tools/llvmc2/CompilationGraph.cpp +++ b/tools/llvmc2/CompilationGraph.cpp @@ -13,13 +13,14 @@ #include "CompilationGraph.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DOTGraphTraits.h" #include "llvm/Support/GraphWriter.h" #include -#include #include +#include #include #include @@ -28,10 +29,13 @@ using namespace llvmc; extern cl::list InputFilenames; extern cl::opt OutputFilename; +extern cl::list Languages; namespace { - // Choose edge that returns + // Go through the list C and find the edge that isEnabled(); if + // there is no such edge, return the default edge; if there is no + // default edge, throw an exception. template const Edge* ChooseEdge(const C& EdgesContainer, const std::string& NodeName = "root") { @@ -47,7 +51,7 @@ namespace { else throw std::runtime_error("Node " + NodeName + ": multiple default outward edges found!" - "Most probably a specification error."); + " Most probably a specification error."); if (E->isEnabled()) return E; } @@ -57,7 +61,7 @@ namespace { else throw std::runtime_error("Node " + NodeName + ": no default outward edge found!" - "Most probably a specification error."); + " Most probably a specification error."); } } @@ -92,8 +96,8 @@ CompilationGraph::getToolsVector(const std::string& LangName) const { tools_map_type::const_iterator I = ToolsMap.find(LangName); if (I == ToolsMap.end()) - throw std::runtime_error("No tools corresponding to " + LangName - + " found!"); + throw std::runtime_error("No tool corresponding to the language " + + LangName + "found!"); return I->second; } @@ -121,15 +125,15 @@ void CompilationGraph::insertEdge(const std::string& A, Edge* E) { B.IncrInEdges(); } -// Make a temporary file named like BaseName-RandomDigits.Suffix -sys::Path MakeTempFile(const sys::Path& TempDir, const std::string& BaseName, - const std::string& Suffix) { - sys::Path Out = TempDir; - Out.appendComponent(BaseName); - Out.appendSuffix(Suffix); - Out.makeUnique(true, NULL); - Out.eraseFromDisk(); - return Out; +namespace { + sys::Path MakeTempFile(const sys::Path& TempDir, const std::string& BaseName, + const std::string& Suffix) { + sys::Path Out = TempDir; + Out.appendComponent(BaseName); + Out.appendSuffix(Suffix); + Out.makeUnique(true, NULL); + return Out; + } } // Pass input file through the chain until we bump into a Join node or @@ -170,6 +174,9 @@ void CompilationGraph::PassThroughGraph (const sys::Path& InFile, if (CurTool->GenerateAction(In, Out).Execute() != 0) throw std::runtime_error("Tool returned error code!"); + if (Last) + return; + CurNode = &getNode(ChooseEdge(CurNode->OutEdges, CurNode->Name())->ToolName()); In = Out; Out.clear(); @@ -212,8 +219,10 @@ TopologicalSortFilterJoinNodes(std::vector& Out) { } // Find head of the toolchain corresponding to the given file. -const Node* CompilationGraph::FindToolChain(const sys::Path& In) const { - const std::string& InLanguage = getLanguage(In); +const Node* CompilationGraph:: +FindToolChain(const sys::Path& In, const std::string* forceLanguage) const { + const std::string& InLanguage = + forceLanguage ? *forceLanguage : getLanguage(In); const tools_vector_type& TV = getToolsVector(InLanguage); if (TV.empty()) throw std::runtime_error("No toolchain corresponding to language" @@ -225,13 +234,55 @@ const Node* CompilationGraph::FindToolChain(const sys::Path& In) const { // temporary variables. int CompilationGraph::Build (const sys::Path& TempDir) { + // This is related to -x option handling. + cl::list::const_iterator xIter = Languages.begin(), + xBegin = xIter, xEnd = Languages.end(); + bool xEmpty = true; + const std::string* xLanguage = 0; + unsigned xPos = 0, xPosNext = 0, filePos = 0; + + if (xIter != xEnd) { + xEmpty = false; + xPos = Languages.getPosition(xIter - xBegin); + cl::list::const_iterator xNext = llvm::next(xIter); + xPosNext = (xNext == xEnd) ? std::numeric_limits::max() + : Languages.getPosition(xNext - xBegin); + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + // For each input file: for (cl::list::const_iterator B = InputFilenames.begin(), - E = InputFilenames.end(); B != E; ++B) { + CB = B, E = InputFilenames.end(); B != E; ++B) { sys::Path In = sys::Path(*B); + // Code for handling the -x option. + // Output: std::string* xLanguage (can be NULL). + if (!xEmpty) { + filePos = InputFilenames.getPosition(B - CB); + + if (xPos < filePos) { + if (filePos < xPosNext) { + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + else { // filePos >= xPosNext + // Skip xIters while filePos > xPosNext + while (filePos > xPosNext) { + ++xIter; + xPos = xPosNext; + + cl::list::const_iterator xNext = llvm::next(xIter); + if (xNext == xEnd) + xPosNext = std::numeric_limits::max(); + else + xPosNext = Languages.getPosition(xNext - xBegin); + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + } + } + } + // Find the toolchain corresponding to this file. - const Node* N = FindToolChain(In); + const Node* N = FindToolChain(In, xLanguage); // Pass file through the chain starting at head. PassThroughGraph(In, N, TempDir); } diff --git a/tools/llvmc2/CompilationGraph.h b/tools/llvmc2/CompilationGraph.h index 72cde9a9e24..4692e5155d7 100644 --- a/tools/llvmc2/CompilationGraph.h +++ b/tools/llvmc2/CompilationGraph.h @@ -165,7 +165,8 @@ namespace llvmc { const llvm::sys::Path& TempDir) const; // Find head of the toolchain corresponding to the given file. - const Node* FindToolChain(const llvm::sys::Path& In) const; + const Node* FindToolChain(const llvm::sys::Path& In, + const std::string* forceLanguage) const; // Sort the nodes in topological order. void TopologicalSort(std::vector& Out); diff --git a/tools/llvmc2/Tools.td b/tools/llvmc2/Tools.td index 64c59ffdeaf..897892415eb 100644 --- a/tools/llvmc2/Tools.td +++ b/tools/llvmc2/Tools.td @@ -56,7 +56,7 @@ def llc : Tool< [(in_language "llvm-bitcode"), (out_language "assembler"), (output_suffix "s"), - (cmd_line "llc $INFILE -o $OUTFILE") + (cmd_line "llc -f $INFILE -o $OUTFILE") ]>; def llvm_gcc_assembler : Tool< @@ -68,6 +68,7 @@ def llvm_gcc_assembler : Tool< (prefix_list_option "Wa", (unpack_values), (help "pass options to assembler")) ]>; +// Default linker def llvm_gcc_linker : Tool< [(in_language "object-code"), (out_language "executable"), @@ -79,6 +80,21 @@ def llvm_gcc_linker : Tool< (prefix_list_option "Wl", (unpack_values), (help "pass options to linker")) ]>; +// Alternative linker for C++ +// TOTHINK: how to implement this best? +// Something like input_file_language can only choose between two languages. +// def llvm_gcc_cpp_linker : Tool< +// [(in_language "object-code"), +// (out_language "executable"), +// (output_suffix "out"), +// (cmd_line "llvm-g++ $INFILE -o $OUTFILE"), +// (join), +// //(input_file_language "c++"), +// (prefix_list_option "L", (forward)), +// (prefix_list_option "l", (forward)), +// (prefix_list_option "Wl", (unpack_values)) +// ]>; + // Language map def LanguageMap : LanguageMap< diff --git a/tools/llvmc2/llvmc.cpp b/tools/llvmc2/llvmc.cpp index b4f0afeb14e..138c30691ac 100644 --- a/tools/llvmc2/llvmc.cpp +++ b/tools/llvmc2/llvmc.cpp @@ -35,6 +35,9 @@ cl::list InputFilenames(cl::Positional, cl::desc(""), cl::ZeroOrMore); cl::opt OutputFilename("o", cl::desc("Output file name"), cl::value_desc("file")); +cl::list Languages("x", + cl::desc("Specify the language of the following input files"), + cl::ZeroOrMore); cl::opt VerboseMode("v", cl::desc("Enable verbose mode")); cl::opt WriteGraph("write-graph",