llvmc: Add a '-time' option.
[oota-llvm.git] / lib / CompilerDriver / Main.cpp
1 //===--- Main.cpp - The LLVM Compiler Driver --------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open
6 // Source License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  llvmc::Main function - driver entry point.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/CompilerDriver/BuiltinOptions.h"
15 #include "llvm/CompilerDriver/CompilationGraph.h"
16 #include "llvm/CompilerDriver/Error.h"
17 #include "llvm/CompilerDriver/Plugin.h"
18
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/System/Path.h"
21
22 #include <sstream>
23 #include <stdexcept>
24 #include <string>
25
26 namespace cl = llvm::cl;
27 namespace sys = llvm::sys;
28 using namespace llvmc;
29
30 namespace {
31
32   std::stringstream* GlobalTimeLog;
33
34   sys::Path getTempDir() {
35     sys::Path tempDir;
36
37     // The --temp-dir option.
38     if (!TempDirname.empty()) {
39       tempDir = TempDirname;
40     }
41     // GCC 4.5-style -save-temps handling.
42     else if (SaveTemps == SaveTempsEnum::Unset) {
43       tempDir = sys::Path::GetTemporaryDirectory();
44       return tempDir;
45     }
46     else if (SaveTemps == SaveTempsEnum::Obj && !OutputFilename.empty()) {
47       tempDir = OutputFilename;
48       tempDir = tempDir.getDirname();
49     }
50     else {
51       // SaveTemps == Cwd --> use current dir (leave tempDir empty).
52       return tempDir;
53     }
54
55     if (!tempDir.exists()) {
56       std::string ErrMsg;
57       if (tempDir.createDirectoryOnDisk(true, &ErrMsg))
58         throw std::runtime_error(ErrMsg);
59     }
60
61     return tempDir;
62   }
63
64   /// BuildTargets - A small wrapper for CompilationGraph::Build.
65   int BuildTargets(CompilationGraph& graph, const LanguageMap& langMap) {
66     int ret;
67     const sys::Path& tempDir = getTempDir();
68     bool toDelete = (SaveTemps == SaveTempsEnum::Unset);
69
70     try {
71       ret = graph.Build(tempDir, langMap);
72     }
73     catch(...) {
74       if (toDelete)
75         tempDir.eraseFromDisk(true);
76       throw;
77     }
78
79     if (toDelete)
80       tempDir.eraseFromDisk(true);
81     return ret;
82   }
83 }
84
85 namespace llvmc {
86
87 // Used to implement -time option. External linkage is intentional.
88 void AppendToGlobalTimeLog(const std::string& cmd, double time) {
89   *GlobalTimeLog << "# " << cmd << ' ' << time << '\n';
90 }
91
92 // Sometimes plugins want to condition on the value in argv[0].
93 const char* ProgramName;
94
95 int Main(int argc, char** argv) {
96   try {
97     LanguageMap langMap;
98     CompilationGraph graph;
99
100     ProgramName = argv[0];
101
102     cl::ParseCommandLineOptions
103       (argc, argv, "LLVM Compiler Driver (Work In Progress)", true);
104
105     PluginLoader Plugins;
106     Plugins.RunInitialization(langMap, graph);
107
108     if (CheckGraph) {
109       int ret = graph.Check();
110       if (!ret)
111         llvm::errs() << "check-graph: no errors found.\n";
112
113       return ret;
114     }
115
116     if (ViewGraph) {
117       graph.viewGraph();
118       if (!WriteGraph)
119         return 0;
120     }
121
122     if (WriteGraph) {
123       graph.writeGraph(OutputFilename.empty()
124                        ? std::string("compilation-graph.dot")
125                        : OutputFilename);
126       return 0;
127     }
128
129     if (InputFilenames.empty()) {
130       throw std::runtime_error("no input files");
131     }
132
133     if (Time) {
134       GlobalTimeLog = new std::stringstream;
135       GlobalTimeLog->precision(2);
136     }
137
138     int ret = BuildTargets(graph, langMap);
139
140     if (Time) {
141       llvm::errs() << GlobalTimeLog->str();
142       delete GlobalTimeLog;
143     }
144
145     return ret;
146   }
147   catch(llvmc::error_code& ec) {
148     return ec.code();
149   }
150   catch(const std::exception& ex) {
151     llvm::errs() << argv[0] << ": " << ex.what() << '\n';
152   }
153   catch(...) {
154     llvm::errs() << argv[0] << ": unknown error!\n";
155   }
156   return 1;
157 }
158
159 } // end namespace llvmc