150155fc3db3c2cbfa21f54415161be8cfe98a3a
[oota-llvm.git] / tools / bugpoint / ToolRunner.cpp
1 //===-- ToolRunner.cpp ----------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the interfaces described in the ToolRunner.h file.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #define DEBUG_TYPE "toolrunner"
15 #include "ToolRunner.h"
16 #include "llvm/Config/config.h"   // for HAVE_LINK_R
17 #include "llvm/System/Program.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/FileUtilities.h"
20 #include <fstream>
21 #include <sstream>
22 #include <iostream>
23 using namespace llvm;
24
25 ToolExecutionError::~ToolExecutionError() throw() { }
26
27 /// RunProgramWithTimeout - This function provides an alternate interface to the
28 /// sys::Program::ExecuteAndWait interface.
29 /// @see sys:Program::ExecuteAndWait
30 static int RunProgramWithTimeout(const sys::Path &ProgramPath,
31                                  const char **Args,
32                                  const sys::Path &StdInFile,
33                                  const sys::Path &StdOutFile,
34                                  const sys::Path &StdErrFile,
35                                  unsigned NumSeconds = 0,
36                                  unsigned MemoryLimit = 0) {
37   const sys::Path* redirects[3];
38   redirects[0] = &StdInFile;
39   redirects[1] = &StdOutFile;
40   redirects[2] = &StdErrFile;
41                                    
42   if (0) {
43     std::cerr << "RUN:";
44     for (unsigned i = 0; Args[i]; ++i)
45       std::cerr << " " << Args[i];
46     std::cerr << "\n";
47   }
48
49   return
50     sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects,
51                                  NumSeconds, MemoryLimit);
52 }
53
54
55
56 static void ProcessFailure(sys::Path ProgPath, const char** Args) {
57   std::ostringstream OS;
58   OS << "\nError running tool:\n ";
59   for (const char **Arg = Args; *Arg; ++Arg)
60     OS << " " << *Arg;
61   OS << "\n";
62
63   // Rerun the compiler, capturing any error messages to print them.
64   sys::Path ErrorFilename("error_messages");
65   std::string ErrMsg;
66   if (ErrorFilename.makeUnique(true, &ErrMsg)) {
67     std::cerr << "Error making unique filename: " << ErrMsg << "\n";
68     exit(1);
69   }
70   RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename,
71                         ErrorFilename); // FIXME: check return code ?
72
73   // Print out the error messages generated by GCC if possible...
74   std::ifstream ErrorFile(ErrorFilename.c_str());
75   if (ErrorFile) {
76     std::copy(std::istreambuf_iterator<char>(ErrorFile),
77               std::istreambuf_iterator<char>(),
78               std::ostreambuf_iterator<char>(OS));
79     ErrorFile.close();
80   }
81
82   ErrorFilename.eraseFromDisk();
83   throw ToolExecutionError(OS.str());
84 }
85
86 //===---------------------------------------------------------------------===//
87 // LLI Implementation of AbstractIntepreter interface
88 //
89 namespace {
90   class LLI : public AbstractInterpreter {
91     std::string LLIPath;          // The path to the LLI executable
92     std::vector<std::string> ToolArgs; // Args to pass to LLI
93   public:
94     LLI(const std::string &Path, const std::vector<std::string> *Args)
95       : LLIPath(Path) {
96       ToolArgs.clear ();
97       if (Args) { ToolArgs = *Args; }
98     }
99
100     virtual int ExecuteProgram(const std::string &Bytecode,
101                                const std::vector<std::string> &Args,
102                                const std::string &InputFile,
103                                const std::string &OutputFile,
104                                const std::vector<std::string> &GCCArgs,
105                                const std::vector<std::string> &SharedLibs =
106                                std::vector<std::string>(),
107                                unsigned Timeout = 0,
108                                unsigned MemoryLimit = 0);
109   };
110 }
111
112 int LLI::ExecuteProgram(const std::string &Bytecode,
113                         const std::vector<std::string> &Args,
114                         const std::string &InputFile,
115                         const std::string &OutputFile,
116                         const std::vector<std::string> &GCCArgs,
117                         const std::vector<std::string> &SharedLibs,
118                         unsigned Timeout,
119                         unsigned MemoryLimit) {
120   if (!SharedLibs.empty())
121     throw ToolExecutionError("LLI currently does not support "
122                              "loading shared libraries.");
123
124   if (!GCCArgs.empty())
125     throw ToolExecutionError("LLI currently does not support "
126                              "GCC Arguments.");
127   std::vector<const char*> LLIArgs;
128   LLIArgs.push_back(LLIPath.c_str());
129   LLIArgs.push_back("-force-interpreter=true");
130
131   // Add any extra LLI args.
132   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
133     LLIArgs.push_back(ToolArgs[i].c_str());
134
135   LLIArgs.push_back(Bytecode.c_str());
136   // Add optional parameters to the running program from Argv
137   for (unsigned i=0, e = Args.size(); i != e; ++i)
138     LLIArgs.push_back(Args[i].c_str());
139   LLIArgs.push_back(0);
140
141   std::cout << "<lli>" << std::flush;
142   DEBUG(std::cerr << "\nAbout to run:\t";
143         for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i)
144           std::cerr << " " << LLIArgs[i];
145         std::cerr << "\n";
146         );
147   return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0],
148       sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
149       Timeout, MemoryLimit);
150 }
151
152 // LLI create method - Try to find the LLI executable
153 AbstractInterpreter *AbstractInterpreter::createLLI(const std::string &ProgPath,
154                                                     std::string &Message,
155                                      const std::vector<std::string> *ToolArgs) {
156   std::string LLIPath = FindExecutable("lli", ProgPath).toString();
157   if (!LLIPath.empty()) {
158     Message = "Found lli: " + LLIPath + "\n";
159     return new LLI(LLIPath, ToolArgs);
160   }
161
162   Message = "Cannot find `lli' in executable directory or PATH!\n";
163   return 0;
164 }
165
166 //===----------------------------------------------------------------------===//
167 // LLC Implementation of AbstractIntepreter interface
168 //
169 GCC::FileType LLC::OutputCode(const std::string &Bytecode, 
170                               sys::Path &OutputAsmFile) {
171   sys::Path uniqueFile(Bytecode+".llc.s");
172   std::string ErrMsg;
173   if (uniqueFile.makeUnique(true, &ErrMsg)) {
174     std::cerr << "Error making unique filename: " << ErrMsg << "\n";
175     exit(1);
176   }
177   OutputAsmFile = uniqueFile;
178   std::vector<const char *> LLCArgs;
179   LLCArgs.push_back (LLCPath.c_str());
180
181   // Add any extra LLC args.
182   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
183     LLCArgs.push_back(ToolArgs[i].c_str());
184
185   LLCArgs.push_back ("-o");
186   LLCArgs.push_back (OutputAsmFile.c_str()); // Output to the Asm file
187   LLCArgs.push_back ("-f");                  // Overwrite as necessary...
188   LLCArgs.push_back (Bytecode.c_str());      // This is the input bytecode
189   LLCArgs.push_back (0);
190
191   std::cout << "<llc>" << std::flush;
192   DEBUG(std::cerr << "\nAbout to run:\t";
193         for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i)
194           std::cerr << " " << LLCArgs[i];
195         std::cerr << "\n";
196         );
197   if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0],
198                             sys::Path(), sys::Path(), sys::Path()))
199     ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]);
200
201   return GCC::AsmFile;                              
202 }
203
204 void LLC::compileProgram(const std::string &Bytecode) {
205   sys::Path OutputAsmFile;
206   OutputCode(Bytecode, OutputAsmFile);
207   OutputAsmFile.eraseFromDisk();
208 }
209
210 int LLC::ExecuteProgram(const std::string &Bytecode,
211                         const std::vector<std::string> &Args,
212                         const std::string &InputFile,
213                         const std::string &OutputFile,
214                         const std::vector<std::string> &ArgsForGCC,
215                         const std::vector<std::string> &SharedLibs,
216                         unsigned Timeout,
217                         unsigned MemoryLimit) {
218
219   sys::Path OutputAsmFile;
220   OutputCode(Bytecode, OutputAsmFile);
221   FileRemover OutFileRemover(OutputAsmFile);
222
223   std::vector<std::string> GCCArgs(ArgsForGCC);
224   GCCArgs.insert(GCCArgs.end(),SharedLibs.begin(),SharedLibs.end());
225
226   // Assuming LLC worked, compile the result with GCC and run it.
227   return gcc->ExecuteProgram(OutputAsmFile.toString(), Args, GCC::AsmFile,
228                              InputFile, OutputFile, GCCArgs,
229                              Timeout, MemoryLimit);
230 }
231
232 /// createLLC - Try to find the LLC executable
233 ///
234 LLC *AbstractInterpreter::createLLC(const std::string &ProgramPath,
235                                     std::string &Message,
236                                     const std::vector<std::string> *Args) {
237   std::string LLCPath = FindExecutable("llc", ProgramPath).toString();
238   if (LLCPath.empty()) {
239     Message = "Cannot find `llc' in executable directory or PATH!\n";
240     return 0;
241   }
242
243   Message = "Found llc: " + LLCPath + "\n";
244   GCC *gcc = GCC::create(ProgramPath, Message);
245   if (!gcc) {
246     std::cerr << Message << "\n";
247     exit(1);
248   }
249   return new LLC(LLCPath, gcc, Args);
250 }
251
252 //===---------------------------------------------------------------------===//
253 // JIT Implementation of AbstractIntepreter interface
254 //
255 namespace {
256   class JIT : public AbstractInterpreter {
257     std::string LLIPath;          // The path to the LLI executable
258     std::vector<std::string> ToolArgs; // Args to pass to LLI
259   public:
260     JIT(const std::string &Path, const std::vector<std::string> *Args)
261       : LLIPath(Path) {
262       ToolArgs.clear ();
263       if (Args) { ToolArgs = *Args; }
264     }
265
266     virtual int ExecuteProgram(const std::string &Bytecode,
267                                const std::vector<std::string> &Args,
268                                const std::string &InputFile,
269                                const std::string &OutputFile,
270                                const std::vector<std::string> &GCCArgs =
271                                  std::vector<std::string>(),
272                                const std::vector<std::string> &SharedLibs =
273                                  std::vector<std::string>(), 
274                                unsigned Timeout =0,
275                                unsigned MemoryLimit =0);
276   };
277 }
278
279 int JIT::ExecuteProgram(const std::string &Bytecode,
280                         const std::vector<std::string> &Args,
281                         const std::string &InputFile,
282                         const std::string &OutputFile,
283                         const std::vector<std::string> &GCCArgs,
284                         const std::vector<std::string> &SharedLibs,
285                         unsigned Timeout,
286                         unsigned MemoryLimit) {
287   if (!GCCArgs.empty())
288     throw ToolExecutionError("JIT does not support GCC Arguments.");
289   // Construct a vector of parameters, incorporating those from the command-line
290   std::vector<const char*> JITArgs;
291   JITArgs.push_back(LLIPath.c_str());
292   JITArgs.push_back("-force-interpreter=false");
293
294   // Add any extra LLI args.
295   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
296     JITArgs.push_back(ToolArgs[i].c_str());
297
298   for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {
299     JITArgs.push_back("-load");
300     JITArgs.push_back(SharedLibs[i].c_str());
301   }
302   JITArgs.push_back(Bytecode.c_str());
303   // Add optional parameters to the running program from Argv
304   for (unsigned i=0, e = Args.size(); i != e; ++i)
305     JITArgs.push_back(Args[i].c_str());
306   JITArgs.push_back(0);
307
308   std::cout << "<jit>" << std::flush;
309   DEBUG(std::cerr << "\nAbout to run:\t";
310         for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i)
311           std::cerr << " " << JITArgs[i];
312         std::cerr << "\n";
313         );
314   DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
315   return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0],
316       sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
317       Timeout, MemoryLimit);
318 }
319
320 /// createJIT - Try to find the LLI executable
321 ///
322 AbstractInterpreter *AbstractInterpreter::createJIT(const std::string &ProgPath,
323                    std::string &Message, const std::vector<std::string> *Args) {
324   std::string LLIPath = FindExecutable("lli", ProgPath).toString();
325   if (!LLIPath.empty()) {
326     Message = "Found lli: " + LLIPath + "\n";
327     return new JIT(LLIPath, Args);
328   }
329
330   Message = "Cannot find `lli' in executable directory or PATH!\n";
331   return 0;
332 }
333
334 GCC::FileType CBE::OutputCode(const std::string &Bytecode,
335                               sys::Path &OutputCFile) {
336   sys::Path uniqueFile(Bytecode+".cbe.c");
337   std::string ErrMsg;
338   if (uniqueFile.makeUnique(true, &ErrMsg)) {
339     std::cerr << "Error making unique filename: " << ErrMsg << "\n";
340     exit(1);
341   }
342   OutputCFile = uniqueFile;
343   std::vector<const char *> LLCArgs;
344   LLCArgs.push_back (LLCPath.c_str());
345
346   // Add any extra LLC args.
347   for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
348     LLCArgs.push_back(ToolArgs[i].c_str());
349
350   LLCArgs.push_back ("-o");
351   LLCArgs.push_back (OutputCFile.c_str());   // Output to the C file
352   LLCArgs.push_back ("-march=c");            // Output C language
353   LLCArgs.push_back ("-f");                  // Overwrite as necessary...
354   LLCArgs.push_back (Bytecode.c_str());      // This is the input bytecode
355   LLCArgs.push_back (0);
356
357   std::cout << "<cbe>" << std::flush;
358   DEBUG(std::cerr << "\nAbout to run:\t";
359         for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i)
360           std::cerr << " " << LLCArgs[i];
361         std::cerr << "\n";
362         );
363   if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(),
364                             sys::Path()))
365     ProcessFailure(LLCPath, &LLCArgs[0]);
366   return GCC::CFile;
367 }
368
369 void CBE::compileProgram(const std::string &Bytecode) {
370   sys::Path OutputCFile;
371   OutputCode(Bytecode, OutputCFile);
372   OutputCFile.eraseFromDisk();
373 }
374
375 int CBE::ExecuteProgram(const std::string &Bytecode,
376                         const std::vector<std::string> &Args,
377                         const std::string &InputFile,
378                         const std::string &OutputFile,
379                         const std::vector<std::string> &ArgsForGCC,
380                         const std::vector<std::string> &SharedLibs,
381                         unsigned Timeout,
382                         unsigned MemoryLimit) {
383   sys::Path OutputCFile;
384   OutputCode(Bytecode, OutputCFile);
385
386   FileRemover CFileRemove(OutputCFile);
387
388   std::vector<std::string> GCCArgs(ArgsForGCC);
389   GCCArgs.insert(GCCArgs.end(),SharedLibs.begin(),SharedLibs.end());
390   return gcc->ExecuteProgram(OutputCFile.toString(), Args, GCC::CFile,
391                              InputFile, OutputFile, GCCArgs,
392                              Timeout, MemoryLimit);
393 }
394
395 /// createCBE - Try to find the 'llc' executable
396 ///
397 CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath,
398                                     std::string &Message,
399                                     const std::vector<std::string> *Args) {
400   sys::Path LLCPath = FindExecutable("llc", ProgramPath);
401   if (LLCPath.isEmpty()) {
402     Message =
403       "Cannot find `llc' in executable directory or PATH!\n";
404     return 0;
405   }
406
407   Message = "Found llc: " + LLCPath.toString() + "\n";
408   GCC *gcc = GCC::create(ProgramPath, Message);
409   if (!gcc) {
410     std::cerr << Message << "\n";
411     exit(1);
412   }
413   return new CBE(LLCPath, gcc, Args);
414 }
415
416 //===---------------------------------------------------------------------===//
417 // GCC abstraction
418 //
419 int GCC::ExecuteProgram(const std::string &ProgramFile,
420                         const std::vector<std::string> &Args,
421                         FileType fileType,
422                         const std::string &InputFile,
423                         const std::string &OutputFile,
424                         const std::vector<std::string> &ArgsForGCC,
425                         unsigned Timeout,
426                         unsigned MemoryLimit) {
427   std::vector<const char*> GCCArgs;
428
429   GCCArgs.push_back(GCCPath.c_str());
430
431   // Specify -x explicitly in case the extension is wonky
432   GCCArgs.push_back("-x");
433   if (fileType == CFile) {
434     GCCArgs.push_back("c");
435     GCCArgs.push_back("-fno-strict-aliasing");
436   } else {
437     GCCArgs.push_back("assembler");
438 #ifdef __APPLE__
439     GCCArgs.push_back("-force_cpusubtype_ALL");
440 #endif
441   }
442   GCCArgs.push_back(ProgramFile.c_str());  // Specify the input filename...
443   GCCArgs.push_back("-x");
444   GCCArgs.push_back("none");
445   GCCArgs.push_back("-o");
446   sys::Path OutputBinary (ProgramFile+".gcc.exe");
447   std::string ErrMsg;
448   if (OutputBinary.makeUnique(true, &ErrMsg)) {
449     std::cerr << "Error making unique filename: " << ErrMsg << "\n";
450     exit(1);
451   }
452   GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
453
454   // Add any arguments intended for GCC. We locate them here because this is
455   // most likely -L and -l options that need to come before other libraries but
456   // after the source. Other options won't be sensitive to placement on the
457   // command line, so this should be safe.
458   for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i)
459     GCCArgs.push_back(ArgsForGCC[i].c_str());
460
461   GCCArgs.push_back("-lm");                // Hard-code the math library...
462   GCCArgs.push_back("-O2");                // Optimize the program a bit...
463 #if defined (HAVE_LINK_R)
464   GCCArgs.push_back("-Wl,-R.");            // Search this dir for .so files
465 #endif
466 #ifdef __sparc__
467   GCCArgs.push_back("-mcpu=v9");
468 #endif
469   GCCArgs.push_back(0);                    // NULL terminator
470
471   std::cout << "<gcc>" << std::flush;
472   DEBUG(std::cerr << "\nAbout to run:\t";
473         for (unsigned i=0, e = GCCArgs.size()-1; i != e; ++i)
474           std::cerr << " " << GCCArgs[i];
475         std::cerr << "\n";
476         );
477   if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(),
478         sys::Path())) {
479     ProcessFailure(GCCPath, &GCCArgs[0]);
480     exit(1);
481   }
482
483   std::vector<const char*> ProgramArgs;
484
485   ProgramArgs.push_back(OutputBinary.c_str());
486   // Add optional parameters to the running program from Argv
487   for (unsigned i=0, e = Args.size(); i != e; ++i)
488     ProgramArgs.push_back(Args[i].c_str());
489   ProgramArgs.push_back(0);                // NULL terminator
490
491   // Now that we have a binary, run it!
492   std::cout << "<program>" << std::flush;
493   DEBUG(std::cerr << "\nAbout to run:\t";
494         for (unsigned i=0, e = ProgramArgs.size()-1; i != e; ++i)
495           std::cerr << " " << ProgramArgs[i];
496         std::cerr << "\n";
497         );
498
499   FileRemover OutputBinaryRemover(OutputBinary);
500   return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
501       sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
502       Timeout, MemoryLimit);
503 }
504
505 int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
506                           std::string &OutputFile,
507                           const std::vector<std::string> &ArgsForGCC) {
508   sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT);
509   std::string ErrMsg;
510   if (uniqueFilename.makeUnique(true, &ErrMsg)) {
511     std::cerr << "Error making unique filename: " << ErrMsg << "\n";
512     exit(1);
513   }
514   OutputFile = uniqueFilename.toString();
515
516   std::vector<const char*> GCCArgs;
517   
518   GCCArgs.push_back(GCCPath.c_str());
519   
520   
521   // Compile the C/asm file into a shared object
522   GCCArgs.push_back("-x");
523   GCCArgs.push_back(fileType == AsmFile ? "assembler" : "c");
524   GCCArgs.push_back("-fno-strict-aliasing");
525   GCCArgs.push_back(InputFile.c_str());   // Specify the input filename.
526 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
527   GCCArgs.push_back("-G");       // Compile a shared library, `-G' for Sparc
528 #elif defined(__APPLE__)
529   // link all source files into a single module in data segment, rather than
530   // generating blocks. dynamic_lookup requires that you set 
531   // MACOSX_DEPLOYMENT_TARGET=10.3 in your env.  FIXME: it would be better for
532   // bugpoint to just pass that in the environment of GCC.
533   GCCArgs.push_back("-single_module");
534   GCCArgs.push_back("-dynamiclib");   // `-dynamiclib' for MacOS X/PowerPC
535   GCCArgs.push_back("-undefined");
536   GCCArgs.push_back("dynamic_lookup");
537 #else
538   GCCArgs.push_back("-shared");  // `-shared' for Linux/X86, maybe others
539 #endif
540
541 #if defined(__ia64__) || defined(__alpha__)
542   GCCArgs.push_back("-fPIC");   // Requires shared objs to contain PIC
543 #endif
544 #ifdef __sparc__
545   GCCArgs.push_back("-mcpu=v9");
546 #endif
547   GCCArgs.push_back("-o");
548   GCCArgs.push_back(OutputFile.c_str()); // Output to the right filename.
549   GCCArgs.push_back("-O2");              // Optimize the program a bit.
550
551   
552   
553   // Add any arguments intended for GCC. We locate them here because this is
554   // most likely -L and -l options that need to come before other libraries but
555   // after the source. Other options won't be sensitive to placement on the
556   // command line, so this should be safe.
557   for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i)
558     GCCArgs.push_back(ArgsForGCC[i].c_str());
559   GCCArgs.push_back(0);                    // NULL terminator
560
561   
562
563   std::cout << "<gcc>" << std::flush;
564   DEBUG(std::cerr << "\nAbout to run:\t";
565         for (unsigned i=0, e = GCCArgs.size()-1; i != e; ++i)
566           std::cerr << " " << GCCArgs[i];
567         std::cerr << "\n";
568         );
569   if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(),
570                             sys::Path())) {
571     ProcessFailure(GCCPath, &GCCArgs[0]);
572     return 1;
573   }
574   return 0;
575 }
576
577 /// create - Try to find the `gcc' executable
578 ///
579 GCC *GCC::create(const std::string &ProgramPath, std::string &Message) {
580   sys::Path GCCPath = FindExecutable("gcc", ProgramPath);
581   if (GCCPath.isEmpty()) {
582     Message = "Cannot find `gcc' in executable directory or PATH!\n";
583     return 0;
584   }
585
586   Message = "Found gcc: " + GCCPath.toString() + "\n";
587   return new GCC(GCCPath);
588 }