blob: f124219a0daf504119f0f0a81fadc9f76305ec62 [file] [log] [blame]
Reid Spencera3f18552004-08-13 20:25:54 +00001//===- CompilerDriver.cpp - The LLVM Compiler Driver ------------*- C++ -*-===//
Reid Spencer5c56dc12004-08-13 20:22:43 +00002//
3//
4// The LLVM Compiler Infrastructure
5//
6// This file was developed by Reid Spencer and is distributed under the
7// University of Illinois Open Source License. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10//
Reid Spencera3f18552004-08-13 20:25:54 +000011// This file implements the bulk of the LLVM Compiler Driver (llvmc).
Reid Spencer5c56dc12004-08-13 20:22:43 +000012//
13//===------------------------------------------------------------------------===
14
15#include "CompilerDriver.h"
Reid Spencerbf437722004-08-15 08:19:46 +000016#include "ConfigLexer.h"
Reid Spencerbae68252004-08-19 04:49:47 +000017#include "Support/SystemUtils.h"
Reid Spencer5c56dc12004-08-13 20:22:43 +000018#include <iostream>
19
20using namespace llvm;
21
22namespace {
23 inline std::string RemoveSuffix(const std::string& fullName) {
24 size_t dotpos = fullName.rfind('.',fullName.size());
25 if ( dotpos == std::string::npos ) return fullName;
26 return fullName.substr(0, dotpos);
27 }
28
29 inline std::string GetSuffix(const std::string& fullName) {
30 size_t dotpos = fullName.rfind('.',fullName.size());
31 if ( dotpos = std::string::npos ) return "";
32 return fullName.substr(dotpos+1);
33 }
Reid Spencer68fb37a2004-08-14 09:37:15 +000034
Reid Spencer5c56dc12004-08-13 20:22:43 +000035 const char OutputSuffix[] = ".o";
36
Reid Spencerbae68252004-08-19 04:49:47 +000037 void WriteAction(CompilerDriver::Action* action ) {
38 std::cerr << action->program;
39 std::vector<std::string>::iterator I = action->args.begin();
40 while (I != action->args.end()) {
Reid Spencer68fb37a2004-08-14 09:37:15 +000041 std::cerr << " " + *I;
42 ++I;
43 }
44 std::cerr << "\n";
45 }
46
Reid Spencerbae68252004-08-19 04:49:47 +000047 void DumpAction(CompilerDriver::Action* action) {
48 std::cerr << "command = " << action->program;
49 std::vector<std::string>::iterator I = action->args.begin();
50 while (I != action->args.end()) {
Reid Spencerbf437722004-08-15 08:19:46 +000051 std::cerr << " " + *I;
52 ++I;
53 }
54 std::cerr << "\n";
Reid Spencerbae68252004-08-19 04:49:47 +000055 std::cerr << "flags = " << action->flags << "\n";
Reid Spencerbf437722004-08-15 08:19:46 +000056 }
57
Reid Spencer68fb37a2004-08-14 09:37:15 +000058 void DumpConfigData(CompilerDriver::ConfigData* cd, const std::string& type ){
59 std::cerr << "Configuration Data For '" << cd->langName << "' (" << type
60 << ")\n";
Reid Spencer68fb37a2004-08-14 09:37:15 +000061 std::cerr << "PreProcessor: ";
Reid Spencerbf437722004-08-15 08:19:46 +000062 DumpAction(&cd->PreProcessor);
Reid Spencer68fb37a2004-08-14 09:37:15 +000063 std::cerr << "Translator: ";
Reid Spencerbf437722004-08-15 08:19:46 +000064 DumpAction(&cd->Translator);
Reid Spencer68fb37a2004-08-14 09:37:15 +000065 std::cerr << "Optimizer: ";
Reid Spencerbf437722004-08-15 08:19:46 +000066 DumpAction(&cd->Optimizer);
Reid Spencer68fb37a2004-08-14 09:37:15 +000067 std::cerr << "Assembler: ";
Reid Spencerbf437722004-08-15 08:19:46 +000068 DumpAction(&cd->Assembler);
Reid Spencer68fb37a2004-08-14 09:37:15 +000069 std::cerr << "Linker: ";
Reid Spencerbf437722004-08-15 08:19:46 +000070 DumpAction(&cd->Linker);
Reid Spencer68fb37a2004-08-14 09:37:15 +000071 }
Reid Spencer5c56dc12004-08-13 20:22:43 +000072
Reid Spencer2a069fa2004-08-16 07:06:38 +000073 void CleanupTempFile(const char* fname) {
74 if (0 == access(fname, F_OK | R_OK))
75 unlink(fname);
76 }
77
78 /// This specifies the passes to run for OPT_FAST_COMPILE (-O1)
79 /// which should reduce the volume of code and make compilation
80 /// faster. This is also safe on any llvm module.
Reid Spencerbae68252004-08-19 04:49:47 +000081 static const char* DefaultFastCompileOptimizations[] = {
82 "-simplifycfg", "-mem2reg", "-instcombine"
Reid Spencer2a069fa2004-08-16 07:06:38 +000083 };
84}
Reid Spencer5c56dc12004-08-13 20:22:43 +000085
Reid Spencerbae68252004-08-19 04:49:47 +000086// Stuff in this namespace properly belongs in lib/System and needs
87// to be portable but we're avoiding that for now.
88namespace sys {
89 std::string MakeTemporaryDirectory() {
90 char temp_name[64];
91 strcpy(temp_name,"/tmp/llvm_XXXXXX");
92 if (0 == mkdtemp(temp_name))
93 throw std::string("Can't create temporary directory");
94 return temp_name;
95 }
96
97 std::string FindExecutableInPath(const std::string& program) {
98 // First, just see if the program is already executable
99 if (isExecutableFile(program)) return program;
100
101 // Get the path. If its empty, we can't do anything
102 const char *PathStr = getenv("PATH");
103 if (PathStr == 0) return "";
104
105 // Now we have a colon separated list of directories to search; try them.
106 unsigned PathLen = strlen(PathStr);
107 while (PathLen) {
108 // Find the first colon...
109 const char *Colon = std::find(PathStr, PathStr+PathLen, ':');
110
111 // Check to see if this first directory contains the executable...
112 std::string FilePath = std::string(PathStr, Colon) + '/' + program;
113 if (isExecutableFile(FilePath))
114 return FilePath; // Found the executable!
115
116 // Nope it wasn't in this directory, check the next range!
117 PathLen -= Colon-PathStr;
118 PathStr = Colon;
119
120 // Advance past duplicate coons
121 while (*PathStr == ':') {
122 PathStr++;
123 PathLen--;
124 }
125 }
126
127 // If we fell out, we ran out of directories in PATH to search, return failure
128 return "";
129 }
130}
131
Reid Spencer5c56dc12004-08-13 20:22:43 +0000132CompilerDriver::CompilerDriver(ConfigDataProvider& confDatProv )
133 : cdp(&confDatProv)
134 , finalPhase(LINKING)
135 , optLevel(OPT_FAST_COMPILE)
136 , isDryRun(false)
137 , isVerbose(false)
138 , isDebug(false)
139 , timeActions(false)
140 , emitRawCode(false)
141 , emitNativeCode(false)
Reid Spencerbae68252004-08-19 04:49:47 +0000142 , keepTemps(false)
Reid Spencer5c56dc12004-08-13 20:22:43 +0000143 , machine()
Reid Spencerbf437722004-08-15 08:19:46 +0000144 , LibraryPaths()
Reid Spencerbae68252004-08-19 04:49:47 +0000145 , AdditionalArgs()
146 , TempDir()
Reid Spencer5c56dc12004-08-13 20:22:43 +0000147{
148 // FIXME: These libraries are platform specific
Reid Spencerbf437722004-08-15 08:19:46 +0000149 LibraryPaths.push_back("/lib");
150 LibraryPaths.push_back("/usr/lib");
Reid Spencerbae68252004-08-19 04:49:47 +0000151 AdditionalArgs.reserve(NUM_PHASES);
152 StringVector emptyVec;
153 for (unsigned i = 0; i < NUM_PHASES; ++i)
154 AdditionalArgs.push_back(emptyVec);
Reid Spencer5c56dc12004-08-13 20:22:43 +0000155}
156
157CompilerDriver::~CompilerDriver() {
158 cdp = 0;
Reid Spencerbf437722004-08-15 08:19:46 +0000159 LibraryPaths.clear();
Reid Spencerbae68252004-08-19 04:49:47 +0000160 AdditionalArgs.clear();
161}
162
163CompilerDriver::ConfigData::ConfigData()
164 : langName()
165 , PreProcessor()
166 , Translator()
167 , Optimizer()
168 , Assembler()
169 , Linker()
170{
171 StringVector emptyVec;
172 for (unsigned i = 0; i < NUM_PHASES; ++i)
173 opts.push_back(emptyVec);
Reid Spencer5c56dc12004-08-13 20:22:43 +0000174}
175
176void CompilerDriver::error( const std::string& errmsg ) {
Reid Spencerbae68252004-08-19 04:49:47 +0000177 std::cerr << "llvmc: Error: " << errmsg << ".\n";
Reid Spencer5c56dc12004-08-13 20:22:43 +0000178 exit(1);
179}
180
181CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd,
182 const std::string& input,
183 const std::string& output,
184 Phases phase)
185{
Reid Spencerbae68252004-08-19 04:49:47 +0000186 Action* pat = 0; ///< The pattern/template for the action
187 Action* action = new Action; ///< The actual action to execute
188
Reid Spencerbf437722004-08-15 08:19:46 +0000189 // Get the action pattern
Reid Spencer5c56dc12004-08-13 20:22:43 +0000190 switch (phase) {
191 case PREPROCESSING: pat = &cd->PreProcessor; break;
192 case TRANSLATION: pat = &cd->Translator; break;
193 case OPTIMIZATION: pat = &cd->Optimizer; break;
194 case ASSEMBLY: pat = &cd->Assembler; break;
195 case LINKING: pat = &cd->Linker; break;
196 default:
197 assert(!"Invalid driver phase!");
198 break;
199 }
200 assert(pat != 0 && "Invalid command pattern");
Reid Spencerbf437722004-08-15 08:19:46 +0000201
Reid Spencerbae68252004-08-19 04:49:47 +0000202 // Copy over some pattern things that don't need to change
203 action->program = pat->program;
204 action->flags = pat->flags;
Reid Spencerbf437722004-08-15 08:19:46 +0000205
Reid Spencerbae68252004-08-19 04:49:47 +0000206 // Do the substitutions from the pattern to the actual
207 StringVector::iterator PI = pat->args.begin();
208 StringVector::iterator PE = pat->args.end();
209 while (PI != PE) {
210 if ((*PI)[0] == '@') {
211 if (*PI == "@in@") {
212 action->args.push_back(input);
213 } else if (*PI == "@out@") {
214 action->args.push_back(output);
215 } else if (*PI == "@time@") {
216 if (timePasses)
217 action->args.push_back("-time-passes");
218 } else if (*PI == "@stats@") {
219 if (showStats)
220 action->args.push_back("-stats");
221 } else if (*PI == "@target@") {
222 // FIXME: Ignore for now
223 } else if (*PI == "@opt@") {
224 if (!emitRawCode) {
225 if (pat->isSet(GROKS_DASH_O)) {
226 if (optLevel != OPT_NONE) {
227 std::string optArg("-O");
228 switch (optLevel) {
229 case OPT_FAST_COMPILE : optArg.append("1"); break;
230 case OPT_SIMPLE: optArg.append("2"); break;
231 case OPT_AGGRESSIVE: optArg.append("3"); break;
232 case OPT_LINK_TIME: optArg.append("4"); break;
233 case OPT_AGGRESSIVE_LINK_TIME: optArg.append("5"); break;
234 default :
235 assert(!"Invalid optimization argument!");
236 optArg.append("0");
237 break;
238 }
239 action->args.push_back(optArg);
240 }
241 } else {
242 if (cd->opts.size() > static_cast<unsigned>(optLevel) &&
243 !cd->opts[optLevel].empty())
244 action->args.insert(action->args.end(), cd->opts[optLevel].begin(),
245 cd->opts[optLevel].end());
246 }
247 }
248 } else {
249 error("Invalid substitution name");
250 }
251 } else {
252 // Its not a substitution, just put it in the action
253 action->args.push_back(*PI);
254 }
255 PI++;
Reid Spencerbf437722004-08-15 08:19:46 +0000256 }
Reid Spencerbae68252004-08-19 04:49:47 +0000257
258 // Get specific options for each kind of action type
259 StringVector& args = AdditionalArgs[phase];
260
261 // Add specific options for each kind of action type
262 action->args.insert(action->args.end(), args.begin(), args.end());
263
264 // Finally, we're done
265 return action;
Reid Spencer5c56dc12004-08-13 20:22:43 +0000266}
267
Reid Spencerbae68252004-08-19 04:49:47 +0000268bool CompilerDriver::DoAction(Action*action) {
269 assert(action != 0 && "Invalid Action!");
Reid Spencer5c56dc12004-08-13 20:22:43 +0000270 if (isVerbose)
Reid Spencerbae68252004-08-19 04:49:47 +0000271 WriteAction(action);
Reid Spencer5c56dc12004-08-13 20:22:43 +0000272 if (!isDryRun) {
Reid Spencerbae68252004-08-19 04:49:47 +0000273 std::string prog(sys::FindExecutableInPath(action->program));
274 if (prog.empty())
275 error("Can't find program '" + action->program + "'");
276
277 // Get the program's arguments
278 const char* argv[action->args.size() + 1];
279 argv[0] = prog.c_str();
280 unsigned i = 1;
281 for (; i <= action->args.size(); ++i)
282 argv[i] = action->args[i-1].c_str();
283 argv[i] = 0;
284
285 // Invoke the program
286 return !ExecWait(argv, environ);
Reid Spencer5c56dc12004-08-13 20:22:43 +0000287 }
Reid Spencerbae68252004-08-19 04:49:47 +0000288 return true;
Reid Spencer5c56dc12004-08-13 20:22:43 +0000289}
290
291int CompilerDriver::execute(const InputList& InpList,
Reid Spencer2a069fa2004-08-16 07:06:38 +0000292 const std::string& Output ) {
Reid Spencer5c56dc12004-08-13 20:22:43 +0000293 // Echo the configuration of options if we're running verbose
294 if (isDebug)
295 {
296 std::cerr << "Compiler Driver Options:\n";
297 std::cerr << "DryRun = " << isDryRun << "\n";
298 std::cerr << "Verbose = " << isVerbose << " \n";
299 std::cerr << "TimeActions = " << timeActions << "\n";
300 std::cerr << "EmitRawCode = " << emitRawCode << "\n";
301 std::cerr << "OutputMachine = " << machine << "\n";
302 std::cerr << "EmitNativeCode = " << emitNativeCode << "\n";
303 InputList::const_iterator I = InpList.begin();
304 while ( I != InpList.end() ) {
305 std::cerr << "Input: " << I->first << "(" << I->second << ")\n";
306 ++I;
307 }
308 std::cerr << "Output: " << Output << "\n";
309 }
310
311 // If there's no input, we're done.
312 if (InpList.empty())
313 error("Nothing to compile.");
314
315 // If they are asking for linking and didn't provide an output
316 // file then its an error (no way for us to "make up" a meaningful
317 // file name based on the various linker input files).
318 if (finalPhase == LINKING && Output.empty())
319 error("An output file name must be specified for linker output");
320
Reid Spencerbf437722004-08-15 08:19:46 +0000321 // This vector holds all the resulting actions of the following loop.
Reid Spencer5c56dc12004-08-13 20:22:43 +0000322 std::vector<Action*> actions;
323
Reid Spencerbf437722004-08-15 08:19:46 +0000324 // Create a temporary directory for our temporary files
Reid Spencerbae68252004-08-19 04:49:47 +0000325 std::string TempDir(sys::MakeTemporaryDirectory());
326 std::string TempPreprocessorOut(TempDir + "/preproc.o");
327 std::string TempTranslatorOut(TempDir + "/trans.o");
328 std::string TempOptimizerOut(TempDir + "/opt.o");
329 std::string TempAssemblerOut(TempDir + "/asm.o");
Reid Spencerbf437722004-08-15 08:19:46 +0000330
Reid Spencer5c56dc12004-08-13 20:22:43 +0000331 /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases
332 // for each input item
333 std::vector<std::string> LinkageItems;
334 InputList::const_iterator I = InpList.begin();
335 while ( I != InpList.end() ) {
336 // Get the suffix of the file name
337 std::string suffix = GetSuffix(I->first);
338
339 // If its a library, bytecode file, or object file, save
340 // it for linking below and short circuit the
341 // pre-processing/translation/assembly phases
342 if (I->second.empty() || suffix == "o" || suffix == "bc") {
343 // We shouldn't get any of these types of files unless we're
344 // later going to link. Enforce this limit now.
345 if (finalPhase != LINKING) {
346 error("Pre-compiled objects found but linking not requested");
347 }
348 LinkageItems.push_back(I->first);
349 continue; // short circuit remainder of loop
350 }
351
352 // At this point, we know its something we need to translate
353 // and/or optimize. See if we can get the configuration data
354 // for this kind of file.
355 ConfigData* cd = cdp->ProvideConfigData(I->second);
356 if (cd == 0)
357 error(std::string("Files of type '") + I->second +
358 "' are not recognized." );
Reid Spencer68fb37a2004-08-14 09:37:15 +0000359 if (isDebug)
360 DumpConfigData(cd,I->second);
Reid Spencer5c56dc12004-08-13 20:22:43 +0000361
362 // We have valid configuration data, now figure out where the output
363 // of compilation should end up.
364 std::string OutFile;
365 if (finalPhase != LINKING) {
366 if (InpList.size() == 1 && !Output.empty())
367 OutFile = Output;
368 else
369 OutFile = RemoveSuffix(I->first) + OutputSuffix;
370 } else {
371 OutFile = Output;
372 }
373
Reid Spencerbae68252004-08-19 04:49:47 +0000374 // Initialize the input file
375 std::string InFile(I->first);
376
Reid Spencerbf437722004-08-15 08:19:46 +0000377 // PRE-PROCESSING PHASE
Reid Spencerbae68252004-08-19 04:49:47 +0000378 Action& action = cd->PreProcessor;
Reid Spencer5c56dc12004-08-13 20:22:43 +0000379
Reid Spencerbf437722004-08-15 08:19:46 +0000380 // Get the preprocessing action, if needed, or error if appropriate
Reid Spencerbae68252004-08-19 04:49:47 +0000381 if (!action.program.empty()) {
382 if (action.isSet(REQUIRED_FLAG) || finalPhase == PREPROCESSING) {
383 if (finalPhase == PREPROCESSING)
384 actions.push_back(GetAction(cd,InFile,OutFile,PREPROCESSING));
385 else {
386 actions.push_back(GetAction(cd,InFile,TempPreprocessorOut,
387 PREPROCESSING));
388 InFile = TempPreprocessorOut;
389 }
Reid Spencerbf437722004-08-15 08:19:46 +0000390 }
391 } else if (finalPhase == PREPROCESSING) {
392 error(cd->langName + " does not support pre-processing");
Reid Spencerbae68252004-08-19 04:49:47 +0000393 } else if (action.isSet(REQUIRED_FLAG)) {
Reid Spencerbf437722004-08-15 08:19:46 +0000394 error(std::string("Don't know how to pre-process ") +
395 cd->langName + " files");
396 }
Reid Spencerbae68252004-08-19 04:49:47 +0000397
Reid Spencer5c56dc12004-08-13 20:22:43 +0000398 // Short-circuit remaining actions if all they want is pre-processing
399 if (finalPhase == PREPROCESSING) { ++I; continue; };
400
401 /// TRANSLATION PHASE
Reid Spencerbae68252004-08-19 04:49:47 +0000402 action = cd->Translator;
Reid Spencerbf437722004-08-15 08:19:46 +0000403
404 // Get the translation action, if needed, or error if appropriate
Reid Spencerbae68252004-08-19 04:49:47 +0000405 if (!action.program.empty()) {
406 if (action.isSet(REQUIRED_FLAG) || finalPhase == TRANSLATION) {
407 if (finalPhase == TRANSLATION)
408 actions.push_back(GetAction(cd,InFile,OutFile,TRANSLATION));
409 else {
410 actions.push_back(GetAction(cd,InFile,TempTranslatorOut,TRANSLATION));
411 InFile = TempTranslatorOut;
412 }
413
414 // ll -> bc Helper
415 if (action.isSet(OUTPUT_IS_ASM_FLAG)) {
416 /// The output of the translator is an LLVM Assembly program
417 /// We need to translate it to bytecode
418 Action* action = new Action();
419 action->program = "llvm-as";
420 action->args.push_back(InFile);
421 action->args.push_back("-o");
422 InFile += ".bc";
423 action->args.push_back(InFile);
424 actions.push_back(action);
425 }
Reid Spencerbf437722004-08-15 08:19:46 +0000426 }
427 } else if (finalPhase == TRANSLATION) {
428 error(cd->langName + " does not support translation");
Reid Spencerbae68252004-08-19 04:49:47 +0000429 } else if (action.isSet(REQUIRED_FLAG)) {
Reid Spencerbf437722004-08-15 08:19:46 +0000430 error(std::string("Don't know how to translate ") +
431 cd->langName + " files");
432 }
Reid Spencerbae68252004-08-19 04:49:47 +0000433
Reid Spencer5c56dc12004-08-13 20:22:43 +0000434 // Short-circuit remaining actions if all they want is translation
435 if (finalPhase == TRANSLATION) { ++I; continue; }
436
437 /// OPTIMIZATION PHASE
Reid Spencerbae68252004-08-19 04:49:47 +0000438 action = cd->Optimizer;
Reid Spencerbf437722004-08-15 08:19:46 +0000439
440 // Get the optimization action, if needed, or error if appropriate
Reid Spencerbae68252004-08-19 04:49:47 +0000441 if (!action.program.empty() && !emitRawCode) {
442 if (action.isSet(REQUIRED_FLAG) || finalPhase == OPTIMIZATION) {
443 if (finalPhase == OPTIMIZATION)
444 actions.push_back(GetAction(cd,InFile,OutFile,OPTIMIZATION));
445 else {
446 actions.push_back(GetAction(cd,InFile,TempOptimizerOut,OPTIMIZATION));
447 InFile = TempOptimizerOut;
448 }
449 // ll -> bc Helper
450 if (action.isSet(OUTPUT_IS_ASM_FLAG)) {
451 /// The output of the translator is an LLVM Assembly program
452 /// We need to translate it to bytecode
453 Action* action = new Action();
454 action->program = "llvm-as";
455 action->args.push_back(InFile);
456 action->args.push_back("-o");
457 InFile += ".bc";
458 action->args.push_back(InFile);
459 actions.push_back(action);
460 }
461 }
Reid Spencerbf437722004-08-15 08:19:46 +0000462 } else if (finalPhase == OPTIMIZATION) {
463 error(cd->langName + " does not support optimization");
Reid Spencerbae68252004-08-19 04:49:47 +0000464 } else if (action.isSet(REQUIRED_FLAG)) {
Reid Spencerbf437722004-08-15 08:19:46 +0000465 error(std::string("Don't know how to optimize ") +
466 cd->langName + " files");
467 }
Reid Spencerbae68252004-08-19 04:49:47 +0000468
Reid Spencer5c56dc12004-08-13 20:22:43 +0000469 // Short-circuit remaining actions if all they want is optimization
470 if (finalPhase == OPTIMIZATION) { ++I; continue; }
471
Reid Spencerbae68252004-08-19 04:49:47 +0000472 /// ASSEMBLY PHASE
473 if (emitNativeCode) {
474 // We must cause native code to be generated
475 } else {
476 }
477
478 // Go to next file to be processed
Reid Spencer5c56dc12004-08-13 20:22:43 +0000479 ++I;
480 }
481
482 /// LINKING PHASE
Reid Spencerbae68252004-08-19 04:49:47 +0000483 if (emitNativeCode) {
484 } else {
485 }
Reid Spencer5c56dc12004-08-13 20:22:43 +0000486
487 /// RUN THE ACTIONS
488 std::vector<Action*>::iterator aIter = actions.begin();
489 while (aIter != actions.end()) {
Reid Spencerbae68252004-08-19 04:49:47 +0000490 if (!DoAction(*aIter))
491 error("Action failed");
Reid Spencer5c56dc12004-08-13 20:22:43 +0000492 aIter++;
493 }
494
Reid Spencerbae68252004-08-19 04:49:47 +0000495 if (!keepTemps) {
496 // Cleanup files
497 CleanupTempFile(TempPreprocessorOut.c_str());
498 CleanupTempFile(TempTranslatorOut.c_str());
499 CleanupTempFile(TempOptimizerOut.c_str());
Reid Spencer2a069fa2004-08-16 07:06:38 +0000500
Reid Spencerbae68252004-08-19 04:49:47 +0000501 // Cleanup temporary directory we created
502 if (0 == access(TempDir.c_str(), F_OK | W_OK))
503 rmdir(TempDir.c_str());
504 }
Reid Spencerbf437722004-08-15 08:19:46 +0000505
Reid Spencer5c56dc12004-08-13 20:22:43 +0000506 return 0;
507}
508
509// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab