Make -save-temps behave like in GCC 4.5.
[oota-llvm.git] / include / llvm / CompilerDriver / Main.inc
1 //===--- Main.inc - 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 //  This tool provides a single point of access to the LLVM
11 //  compilation tools.  It has many options. To discover the options
12 //  supported please refer to the tools' manual page or run the tool
13 //  with the --help option.
14 //
15 //===----------------------------------------------------------------------===//
16
17 #ifndef LLVM_INCLUDE_COMPILER_DRIVER_MAIN_INC
18 #define LLVM_INCLUDE_COMPILER_DRIVER_MAIN_INC
19
20 #include "llvm/CompilerDriver/BuiltinOptions.h"
21 #include "llvm/CompilerDriver/CompilationGraph.h"
22 #include "llvm/CompilerDriver/Error.h"
23 #include "llvm/CompilerDriver/ForceLinkage.h"
24 #include "llvm/CompilerDriver/Plugin.h"
25
26 #include "llvm/System/Path.h"
27 #include "llvm/Support/CommandLine.h"
28 #include "llvm/Support/PluginLoader.h"
29
30 #include <iostream>
31 #include <stdexcept>
32 #include <string>
33
34 namespace cl = llvm::cl;
35 namespace sys = llvm::sys;
36 using namespace llvmc;
37
38 // Built-in command-line options.
39 // External linkage here is intentional.
40
41 cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input file>"),
42                                      cl::ZeroOrMore);
43 cl::opt<std::string> OutputFilename("o", cl::desc("Output file name"),
44                                     cl::value_desc("file"), cl::Prefix);
45 cl::list<std::string> Languages("x",
46           cl::desc("Specify the language of the following input files"),
47           cl::ZeroOrMore);
48 cl::opt<bool> DryRun("dry-run",
49                      cl::desc("Only pretend to run commands"));
50 cl::opt<bool> VerboseMode("v",
51                           cl::desc("Enable verbose mode"));
52
53 cl::opt<bool> CheckGraph("check-graph",
54                          cl::desc("Check the compilation graph for errors"),
55                          cl::Hidden);
56 cl::opt<bool> WriteGraph("write-graph",
57                          cl::desc("Write compilation-graph.dot file"),
58                          cl::Hidden);
59 cl::opt<bool> ViewGraph("view-graph",
60                          cl::desc("Show compilation graph in GhostView"),
61                          cl::Hidden);
62
63 cl::opt<SaveTempsEnum::Values> SaveTemps
64 ("save-temps", cl::desc("Keep temporary files"),
65  cl::init(SaveTempsEnum::Unset),
66  cl::values(clEnumValN(SaveTempsEnum::Obj, "obj",
67                        "Save files in the directory specified with -o"),
68             clEnumValN(SaveTempsEnum::Cwd, "cwd",
69                        "Use current working directory"),
70             clEnumValN(SaveTempsEnum::Obj, "", "Same as 'cwd'"),
71             clEnumValEnd),
72  cl::ValueOptional);
73
74 namespace {
75
76   sys::Path getTempDir() {
77     sys::Path tempDir;
78
79     // GCC 4.5-style -save-temps handling.
80     if (SaveTemps == SaveTempsEnum::Unset) {
81       tempDir = sys::Path::GetTemporaryDirectory();
82     }
83     else if (SaveTemps == SaveTempsEnum::Obj && !OutputFilename.empty()) {
84       tempDir = OutputFilename;
85
86       if (!tempDir.exists()) {
87         std::string ErrMsg;
88         if (tempDir.createDirectoryOnDisk(true, &ErrMsg))
89           throw std::runtime_error(ErrMsg);
90       }
91     }
92     // else if (SaveTemps == Cwd) -> use current dir (leave tempDir empty)
93
94     return tempDir;
95   }
96
97   /// BuildTargets - A small wrapper for CompilationGraph::Build.
98   int BuildTargets(CompilationGraph& graph, const LanguageMap& langMap) {
99     int ret;
100     const sys::Path& tempDir = getTempDir();
101
102     try {
103       ret = graph.Build(tempDir, langMap);
104     }
105     catch(...) {
106       if (SaveTemps == SaveTempsEnum::Unset)
107         tempDir.eraseFromDisk(true);
108       throw;
109     }
110
111     if (SaveTemps == SaveTempsEnum::Unset)
112       tempDir.eraseFromDisk(true);
113     return ret;
114   }
115 }
116
117 int main(int argc, char** argv) {
118   try {
119     ForceLinkage();
120
121     LanguageMap langMap;
122     CompilationGraph graph;
123
124     cl::ParseCommandLineOptions
125       (argc, argv, "LLVM Compiler Driver (Work In Progress)", true);
126
127     PluginLoader Plugins;
128     Plugins.PopulateLanguageMap(langMap);
129     Plugins.PopulateCompilationGraph(graph);
130
131     if (CheckGraph) {
132       int ret = graph.Check();
133       if (!ret)
134         std::cerr << "check-graph: no errors found.\n";
135
136       return ret;
137     }
138
139     if (ViewGraph) {
140       graph.viewGraph();
141       if (!WriteGraph)
142         return 0;
143     }
144
145     if (WriteGraph) {
146       graph.writeGraph(OutputFilename.empty()
147                        ? std::string("compilation-graph.dot")
148                        : OutputFilename);
149       return 0;
150     }
151
152     if (InputFilenames.empty()) {
153       throw std::runtime_error("no input files");
154     }
155
156     return BuildTargets(graph, langMap);
157   }
158   catch(llvmc::error_code& ec) {
159     return ec.code();
160   }
161   catch(const std::exception& ex) {
162     std::cerr << argv[0] << ": " << ex.what() << '\n';
163   }
164   catch(...) {
165     std::cerr << argv[0] << ": unknown error!\n";
166   }
167   return 1;
168 }
169
170 #endif // LLVM_INCLUDE_COMPILER_DRIVER_MAIN_INC