2002-07-11 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / driver.cs
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10
11 namespace Mono.CSharp
12 {
13         using System;
14         using System.Reflection;
15         using System.Reflection.Emit;
16         using System.Collections;
17         using System.IO;
18         using System.Globalization;
19         using Mono.Languages;
20
21         enum Target {
22                 Library, Exe, Module, WinExe
23         };
24         
25         /// <summary>
26         ///    The compiler driver.
27         /// </summary>
28         public class Driver
29         {
30                 
31                 //
32                 // Assemblies references to be linked.   Initialized with
33                 // mscorlib.dll here.
34                 static ArrayList references;
35
36                 //
37                 // If any of these fail, we ignore the problem.  This is so
38                 // that we can list all the assemblies in Windows and not fail
39                 // if they are missing on Linux.
40                 //
41                 static ArrayList soft_references;
42
43                 // Lookup paths
44                 static ArrayList link_paths;
45
46                 // Whether we want Yacc to output its progress
47                 static bool yacc_verbose = false;
48
49                 // Whether we want to only run the tokenizer
50                 static bool tokenize = false;
51                 
52                 static string first_source;
53
54                 static Target target = Target.Exe;
55                 static string target_ext = ".exe";
56
57                 static bool want_debugging_support = false;
58                 static ArrayList debug_arglist = new ArrayList ();
59
60                 static bool parse_only = false;
61                 static bool timestamps = false;
62
63                 //
64                 // Whether to load the initial config file (what CSC.RSP has by default)
65                 // 
66                 static bool load_default_config = true;
67
68                 static Hashtable response_file_list;
69                 static Hashtable source_files = new Hashtable ();
70
71                 //
72                 // A list of resource files
73                 //
74                 static ArrayList resources;
75                 
76                 //
77                 // An array of the defines from the command line
78                 //
79                 static ArrayList defines;
80
81                 //
82                 // Output file
83                 //
84                 static string output_file = null;
85                 
86                 //
87                 // Last time we took the time
88                 //
89                 static DateTime last_time;
90                 static void ShowTime (string msg)
91                 {
92                         DateTime now = DateTime.Now;
93                         TimeSpan span = now - last_time;
94                         last_time = now;
95
96                         Console.WriteLine (
97                                 "[{0:00}:{1:000}] {2}",
98                                 (int) span.TotalSeconds, span.Milliseconds, msg);
99                 }
100                
101                 static void tokenize_file (string input_file)
102                 {
103                         Stream input;
104
105                         try {
106                                 input = File.OpenRead (input_file);
107                         } catch {
108                                 Report.Error (2001, "Source file '" + input_file + "' could not be opened");
109                                 return;
110                         }
111
112                         using (input){
113                                 Tokenizer lexer = new Tokenizer (input, input_file, defines);
114                                 int token, tokens = 0, errors = 0;
115
116                                 while ((token = lexer.token ()) != Token.EOF){
117                                         Location l = lexer.Location;
118                                         tokens++;
119                                         if (token == Token.ERROR)
120                                                 errors++;
121                                 }
122                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
123                         }
124                         
125                         return;
126                 }
127
128                 // MonoTODO("Change error code for aborted compilation to something reasonable")]               
129                 static void parse (string input_file)
130                 {
131                         CSharpParser parser;
132                         Stream input;
133
134                         try {
135                                 input = File.OpenRead (input_file);
136                         } catch {
137                                 Report.Error (2001, "Source file '" + input_file + "' could not be opened");
138                                 return;
139                         }
140
141                         parser = new CSharpParser (input_file, input, defines);
142                         parser.yacc_verbose = yacc_verbose;
143                         try {
144                                 parser.parse ();
145                         } catch (Exception ex) {
146                                 Report.Error(666, "Compilation aborted: " + ex);
147                         } finally {
148                                 input.Close ();
149                         }
150                 }
151                 
152                 static void Usage ()
153                 {
154                         Console.WriteLine (
155                                 "Mono C# compiler, (C) 2001 Ximian, Inc.\n" +
156                                 "mcs [options] source-files\n" +
157                                 "   --about          About the Mono C# compiler\n" +
158                                 "   --checked        Set default context to checked\n" +
159                                 "   --define SYM     Defines the symbol SYM\n" +
160                                 "   --debug          Generate debugging information\n" + 
161                                 "   -g               Generate debugging information\n" +
162                                 "   --debug-args X   Specify additional arguments for the\n" +
163                                 "                    symbol writer.\n" +
164                                 "   --fatal          Makes errors fatal\n" +
165                                 "   -L PATH          Adds PATH to the assembly link path\n" +
166                                 "   --noconfig       Disables implicit references to assemblies\n" +
167                                 "   --nostdlib       Does not load core libraries\n" +
168                                 "   --nowarn XXX     Ignores warning number XXX\n" +
169                                 "   -o FNAME         Specifies output file\n" +
170                                 "   -g, --debug      Write symbolic debugging information to FILE-debug.s\n" +
171                                 "   --parse          Only parses the source file\n" +
172                                 "   --expect-error X Expect that error X will be encountered\n" +
173                                 "   --recurse SPEC   Recursively compiles the files in SPEC ([dir]/file)\n" + 
174                                 "   --resource FILE  Addds FILE as a resource\n" + 
175                                 "   --stacktrace     Shows stack trace at error location\n" +
176                                 "   --target KIND    Specifies the target (KIND is one of: exe, winexe, " +
177                                                      "library, module)\n" +
178                                 "   --timestamp      Displays time stamps of various compiler events\n" +
179                                 "   --unsafe         Allows unsafe code\n" +
180                                 "   --werror         Treat warnings as errors\n" +
181                                 "   --wlevel LEVEL   Sets warning level (the highest is 4, the default)\n" +
182                                 "   -r               References an assembly\n" +
183                                 "   -v               Verbose parsing (for debugging the parser)\n" +
184                                 "   @file            Read response file for more options");
185                 }
186
187                 static void About ()
188                 {
189                         Console.WriteLine (
190                                 "The Mono C# compiler is (C) 2001 Ximian, Inc.\n\n" +
191                                 "The compiler source code is released under the terms of the GNU GPL\n\n" +
192
193                                 "For more information on Mono, visit the project Web site\n" +
194                                 "   http://www.go-mono.com\n\n" +
195
196                                 "The compiler was written by Miguel de Icaza and Ravi Pratap");
197                 }
198                 
199                 public static int Main (string[] args)
200                 {
201                         bool ok = MainDriver (args);
202                         
203                         if (ok && Report.Errors == 0) {
204                                 Console.Write("Compilation succeeded");
205                                 if (Report.Warnings > 0) {
206                                         Console.Write(" - {0} warning(s)", Report.Warnings);
207                                 } 
208                                 Console.WriteLine();
209                                 return 0;
210                         } else {
211                                 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
212                                         Report.Errors, Report.Warnings);
213                                 return 1;
214                         }
215                 }
216
217                 static public void LoadAssembly (string assembly, bool soft)
218                 {
219                         Assembly a;
220                         string total_log = "";
221
222                         try {
223                                 char[] path_chars = { '/', '\\', '.' };
224
225                                 if (assembly.IndexOfAny (path_chars) != -1) {
226                                         a = Assembly.LoadFrom (assembly);
227                                 } else {
228                                         a = Assembly.Load (assembly);
229                                 }
230                                 TypeManager.AddAssembly (a);
231
232                         } catch (FileNotFoundException){
233                                 foreach (string dir in link_paths){
234                                         string full_path = dir + "/" + assembly + ".dll";
235
236                                         try {
237                                                 a = Assembly.LoadFrom (full_path);
238                                                 TypeManager.AddAssembly (a);
239                                                 return;
240                                         } catch (FileNotFoundException ff) {
241                                                 total_log += ff.FusionLog;
242                                                 continue;
243                                         }
244                                 }
245                                 if (!soft) {
246                                         Report.Error (6, "Cannot find assembly `" + assembly + "'" );
247                                         Console.WriteLine ("Log: \n" + total_log);
248                                 }
249                         } catch (BadImageFormatException f) {
250                                 Report.Error(6, "Cannot load assembly (bad file format)" + f.FusionLog);
251                         } catch (FileLoadException f){
252                                 Report.Error(6, "Cannot load assembly " + f.FusionLog);
253                         } catch (ArgumentNullException){
254                                 Report.Error(6, "Cannot load assembly (null argument)");
255                         }
256                 }
257
258                 /// <summary>
259                 ///   Loads all assemblies referenced on the command line
260                 /// </summary>
261                 static public void LoadReferences ()
262                 {
263                         foreach (string r in references)
264                                 LoadAssembly (r, false);
265
266                         foreach (string r in soft_references)
267                                 LoadAssembly (r, true);
268                         
269                         return;
270                 }
271
272                 static void SetupDefaultDefines ()
273                 {
274                         defines = new ArrayList ();
275                         defines.Add ("__MonoCS__");
276                 }
277
278                 static string [] LoadArgs (string file)
279                 {
280                         StreamReader f;
281                         ArrayList args = new ArrayList ();
282                         string line;
283                         try {
284                                 f = new StreamReader (file);
285                         } catch {
286                                 return null;
287                         }
288
289                         while ((line = f.ReadLine ()) != null){
290                                 string [] line_args = line.Split (new char [] { ' ' });
291
292                                 foreach (string arg in line_args)
293                                         args.Add (arg);
294                         }
295
296                         string [] ret_value = new string [args.Count];
297                         args.CopyTo (ret_value, 0);
298
299                         return ret_value;
300                 }
301
302                 //
303                 // Returns the directory where the system assemblies are installed
304                 //
305                 static string GetSystemDir ()
306                 {
307                         Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
308
309                         foreach (Assembly a in assemblies){
310                                 string codebase = a.CodeBase;
311                                 if (codebase.EndsWith ("corlib.dll")){
312                                         return codebase.Substring (0, codebase.LastIndexOf ("/"));
313                                 }
314                         }
315
316                         Report.Error (-15, "Can not compute my system path");
317                         return "";
318                 }
319
320                 //
321                 // Given a path specification, splits the path from the file/pattern
322                 //
323                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
324                 {
325                         int p = spec.LastIndexOf ("/");
326                         if (p != -1){
327                                 //
328                                 // Windows does not like /file.cs, switch that to:
329                                 // "\", "file.cs"
330                                 //
331                                 if (p == 0){
332                                         path = "\\";
333                                         pattern = spec.Substring (1);
334                                 } else {
335                                         path = spec.Substring (0, p);
336                                         pattern = spec.Substring (p + 1);
337                                 }
338                                 return;
339                         }
340
341                         p = spec.LastIndexOf ("\\");
342                         if (p != -1){
343                                 path = spec.Substring (0, p);
344                                 pattern = spec.Substring (p + 1);
345                                 return;
346                         }
347
348                         path = ".";
349                         pattern = spec;
350                 }
351
352                 static void ProcessFile (string f)
353                 {
354                         if (first_source == null)
355                                 first_source = f;
356
357                         if (source_files.Contains (f)){
358                                 Report.Error (
359                                         1516,
360                                         "Source file `" + f + "' specified multiple times");
361                                 Environment.Exit (1);
362                         } else
363                                 source_files.Add (f, f);
364                                         
365                         if (tokenize) {
366                                 tokenize_file (f);
367                         } else {
368                                 parse (f);
369                         }
370                 }
371
372                 static void CompileFiles (string spec, bool recurse)
373                 {
374                         string path, pattern;
375
376                         SplitPathAndPattern (spec, out path, out pattern);
377                         if (pattern.IndexOf ("*") == -1){
378                                 ProcessFile (spec);
379                                 return;
380                         }
381
382                         string [] files = null;
383                         try {
384                                 files = Directory.GetFiles (path, pattern);
385                         } catch (System.IO.DirectoryNotFoundException) {
386                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
387                                 return;
388                         } catch (System.IO.IOException){
389                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
390                                 return;
391                         }
392                         foreach (string f in files) {
393                                 ProcessFile (f);
394                         }
395
396                         if (!recurse)
397                                 return;
398                         
399                         string [] dirs = null;
400
401                         try {
402                                 dirs = Directory.GetDirectories (path);
403                         } catch {
404                         }
405                         
406                         foreach (string d in dirs) {
407                                         
408                                 // Don't include path in this string, as each
409                                 // directory entry already does
410                                 CompileFiles (d + "/" + pattern, true);
411                         }
412                 }
413
414                 static void DefineDefaultConfig ()
415                 {
416                         //
417                         // For now the "default config" is harcoded into the compiler
418                         // we can move this outside later
419                         //
420                         string [] default_config = {
421                                 "System",
422                                 "System.Xml",
423 #if false
424                                 //
425                                 // Is it worth pre-loading all this stuff?
426                                 //
427                                 "Accessibility",
428                                 "System.Configuration.Install",
429                                 "System.Data",
430                                 "System.Design",
431                                 "System.DirectoryServices",
432                                 "System.Drawing.Design",
433                                 "System.Drawing",
434                                 "System.EnterpriseServices",
435                                 "System.Management",
436                                 "System.Messaging",
437                                 "System.Runtime.Remoting",
438                                 "System.Runtime.Serialization.Formatters.Soap",
439                                 "System.Security",
440                                 "System.ServiceProcess",
441                                 "System.Web",
442                                 "System.Web.RegularExpressions",
443                                 "System.Web.Services",
444                                 "System.Windows.Forms"
445 #endif
446                         };
447                         
448                         int p = 0;
449                         foreach (string def in default_config)
450                                 soft_references.Insert (p++, def);
451                 }
452
453                 static void SetOutputFile (string name)
454                 {
455                         output_file = name;
456                         string bname = CodeGen.Basename (output_file);
457                         if (bname.IndexOf (".") == -1)
458                                 output_file += ".exe";
459                 }
460
461                 static void SetWarningLevel (string s)
462                 {
463                         int level = 0;
464
465                         try {
466                                 level = Int32.Parse (s);
467                         } catch {
468                                 Report.Error (
469                                         1900,
470                                         "--wlevel requires an value from 0 to 4");
471                                 Environment.Exit (1);
472                         }
473                         if (level < 0 || level > 4){
474                                 Report.Error (1900, "Warning level must be 0 to 4");
475                                 Environment.Exit (1);
476                         } else
477                                 RootContext.WarningLevel = level;
478                 }
479                 //
480                 // Currently handles the Unix-like command line options, but will be
481                 // deprecated in favor of the CSCParseOption, which will also handle the
482                 // options that start with a dash in the future.
483                 //
484                 static bool UnixParseOption (string arg, ref string [] args, ref int i)
485                 {
486                         switch (arg){
487                         case "-v":
488                                 yacc_verbose = true;
489                                 return true;
490                                 
491                         case "--parse":
492                                 parse_only = true;
493                                 return true;
494                                 
495                         case "--main": case "-m":
496                                 if ((i + 1) >= args.Length){
497                                         Usage ();
498                                         Environment.Exit (1);
499                                 }
500                                 RootContext.MainClass = args [++i];
501                                 return true;
502                                 
503                         case "--unsafe":
504                                 RootContext.Unsafe = true;
505                                 return true;
506                                 
507                         case "/?": case "/h": case "/help":
508                         case "--help":
509                                 Usage ();
510                                 Environment.Exit (0);
511                                 return true;
512                                 
513                         case "--define":
514                                 if ((i + 1) >= args.Length){
515                                         Usage ();
516                                         Environment.Exit (1);
517                                 }
518                                 defines.Add (args [++i]);
519                                 return true;
520                                 
521                         case "--expect-error": {
522                                 int code = 0;
523                                 
524                                 try {
525                                         code = Int32.Parse (
526                                                 args [++i], NumberStyles.AllowLeadingSign);
527                                         Report.ExpectedError = code;
528                                 } catch {
529                                         Report.Error (-14, "Invalid number specified");
530                                 } 
531                                 return true;
532                         }
533                                 
534                         case "--tokenize": 
535                                 tokenize = true;
536                                 return true;
537                                 
538                         case "-o": 
539                         case "--output":
540                                 if ((i + 1) >= args.Length){
541                                         Usage ();
542                                         Environment.Exit (1);
543                                 }
544                                 SetOutputFile (args [++i]);
545                                 return true;
546                                 
547                         case "--checked":
548                                 RootContext.Checked = true;
549                                 return true;
550                                 
551                         case "--stacktrace":
552                                 Report.Stacktrace = true;
553                                 return true;
554                                 
555                         case "--resource":
556                                 if ((i + 1) >= args.Length){
557                                         Usage ();
558                                         Console.WriteLine("Missing argument to --resource"); 
559                                         Environment.Exit (1);
560                                 }
561                                 if (resources == null)
562                                         resources = new ArrayList ();
563                                 
564                                 resources.Add (args [++i]);
565                                 return true;
566                                 
567                         case "--target":
568                                 if ((i + 1) >= args.Length){
569                                         Environment.Exit (1);
570                                         return true;
571                                 }
572                                 
573                                 string type = args [++i];
574                                 switch (type){
575                                 case "library":
576                                         target = Target.Library;
577                                         target_ext = ".dll";
578                                         break;
579                                         
580                                 case "exe":
581                                         target = Target.Exe;
582                                         break;
583                                         
584                                 case "winexe":
585                                         target = Target.WinExe;
586                                         break;
587                                         
588                                 case "module":
589                                         target = Target.Module;
590                                         target_ext = ".dll";
591                                         break;
592                                 default:
593                                         Usage ();
594                                         Environment.Exit (1);
595                                         break;
596                                 }
597                                 return true;
598                                 
599                         case "-r":
600                                 if ((i + 1) >= args.Length){
601                                         Usage ();
602                                         Environment.Exit (1);
603                                 }
604                                 
605                                 references.Add (args [++i]);
606                                 return true;
607                                 
608                         case "-L":
609                                 if ((i + 1) >= args.Length){
610                                         Usage ();       
611                                         Environment.Exit (1);
612                                 }
613                                 link_paths.Add (args [++i]);
614                                 return true;
615                                 
616                         case "--nostdlib":
617                                 RootContext.StdLib = false;
618                                 return true;
619                                 
620                         case "--fatal":
621                                 Report.Fatal = true;
622                                 return true;
623                                 
624                         case "--werror":
625                                 Report.WarningsAreErrors = true;
626                                 return true;
627                                 
628                         case "--nowarn":
629                                 if ((i + 1) >= args.Length){
630                                         Usage ();
631                                         Environment.Exit (1);
632                                 }
633                                 int warn = 0;
634                                 
635                                 try {
636                                         warn = Int32.Parse (args [++i]);
637                                 } catch {
638                                         Usage ();
639                                         Environment.Exit (1);
640                                 }
641                                 Report.SetIgnoreWarning (warn);
642                                 return true;
643                                 
644                         case "--wlevel":
645                                 if ((i + 1) >= args.Length){
646                                         Report.Error (
647                                                 1900,
648                                                 "--wlevel requires an value from 0 to 4");
649                                         Environment.Exit (1);
650                                 }
651
652                                 SetWarningLevel (args [++i]);
653                                 return true;
654                                 
655                         case "--about":
656                                 About ();
657                                 return true;
658                                 
659                         case "--recurse":
660                                 if ((i + 1) >= args.Length){
661                                         Console.WriteLine ("--recurse requires an argument");
662                                         Environment.Exit (1);
663                                 }
664                                 CompileFiles (args [++i], true); 
665                                 return true;
666                                 
667                         case "--timestamp":
668                                 timestamps = true;
669                                 last_time = DateTime.Now;
670                                 debug_arglist.Add ("timestamp");
671                                 return true;
672                                 
673                         case "--debug": case "-g":
674                                 want_debugging_support = true;
675                                 return true;
676                                 
677                         case "--debug-args":
678                                 if ((i + 1) >= args.Length){
679                                         Console.WriteLine ("--debug-args requires an argument");
680                                         Environment.Exit (1);
681                                 }
682                                 char[] sep = { ',' };
683                                 debug_arglist.AddRange (args [++i].Split (sep));
684                                 return true;
685                                 
686                         case "--noconfig":
687                                 load_default_config = false;
688                                 return true;
689                                 
690                         default:
691                                 Report.Warning(666, "Unknown option: " + arg);
692                                 return true;
693                         }
694                 }
695
696                 //
697                 // Currently it is very basic option parsing, but eventually, this will
698                 // be the complete option parser
699                 //
700                 static bool CSCParseOption (string option, ref string [] args, ref int i)
701                 {
702                         int idx = option.IndexOf (":");
703                         string arg, value;
704
705                         if (idx == -1){
706                                 arg = option;
707                                 value = "";
708                         } else {
709                                 arg = option.Substring (0, idx);
710
711                                 value = option.Substring (idx + 1);
712                         }
713
714                         switch (arg){
715                         case "/nologo":
716                                 return true;
717
718                         case "/t":
719                         case "/target":
720                                 switch (value){
721                                 case "exe":
722                                         target = Target.Exe;
723                                         break;
724
725                                 case "winexe":
726                                         target = Target.WinExe;
727                                         break;
728
729                                 case "library":
730                                         target = Target.Library;
731                                         target_ext = ".dll";
732                                         break;
733
734                                 case "module":
735                                         target = Target.Module;
736                                         target_ext = ".dll";
737                                         break;
738
739                                 default:
740                                         Usage ();
741                                         Environment.Exit (1);
742                                         break;
743                                 }
744                                 return true;
745
746                         case "/out:":
747                                 if (value == ""){
748                                         Usage ();
749                                         Environment.Exit (1);
750                                 }
751                                 SetOutputFile (value);
752                                 return true;
753
754                         case "/optimize":
755                         case "/optimize+":
756                         case "/optimize-":
757                         case "/incremental":
758                         case "/incremental+":
759                         case "/incremental-":
760                                 // nothing.
761                                 return true;
762
763                         case "/d":
764                         case "/define": {
765                                 string [] defs;
766
767                                 if (value == ""){
768                                         Usage ();
769                                         Environment.Exit (1);
770                                 }
771                                 
772                                 defs = value.Split (new Char [] {';'});
773                                 foreach (string d in defs)
774                                         defines.Add (d);
775                                 return true;
776                         }
777
778                         case "/recurse":
779                                 if (value == ""){
780                                         Console.WriteLine ("/recurse requires an argument");
781                                         Environment.Exit (1);
782                                 }
783                                 CompileFiles (args [++i], true); 
784                                 return true;
785
786                         case "/r":
787                         case "/reference":
788                                 Console.WriteLine ("/r and /reference not supported, use -r which will give you MCS semantics");
789                                 Console.WriteLine ("this will be fixed shortly");
790                                 Environment.Exit (1);
791                                 return true;
792
793                         case "/lib":
794                                 Console.WriteLine ("/lib is not  supported, use -L which will give you MCS semantics");
795                                 Console.WriteLine ("this will be fixed shortly");
796                                 Environment.Exit (1);
797                                 return true;
798                                 
799                         case "/debug":
800                         case "/debug+":
801                                 want_debugging_support = true;
802                                 return true;
803
804                         case "/checked":
805                         case "/checked+":
806                                 RootContext.Checked = true;
807                                 return true;
808
809                         case "/checked-":
810                                 RootContext.Checked = false;
811                                 return true;
812
813                         case "/unsafe":
814                         case "/unsafe+":
815                                 RootContext.Unsafe = true;
816                                 return true;
817
818                         case "/unsafe-":
819                                 RootContext.Unsafe = false;
820                                 return true;
821
822                         case "/warnaserror":
823                         case "/warnaserror+":
824                                 Report.WarningsAreErrors = true;
825                                 return true;
826
827                         case "/warnaserror-":
828                                 Report.WarningsAreErrors = false;
829                                 return true;
830
831                         case "/warn":
832                                 SetWarningLevel (value);
833                                 return true;
834
835                         case "/nowarn": {
836                                 string [] warns;
837
838                                 if (value == ""){
839                                         Usage ();
840                                         Environment.Exit (1);
841                                 }
842                                 
843                                 warns = value.Split (new Char [] {','});
844                                 foreach (string wc in warns){
845                                         int warn = 0;
846                                         
847                                         try {
848                                                 warn = Int32.Parse (wc);
849                                         } catch {
850                                                 Usage ();
851                                                 Environment.Exit (1);
852                                         }
853                                         Report.SetIgnoreWarning (warn);
854                                 }
855                                 return true;
856                         }
857
858                         case "/noconfig":
859                                 load_default_config = false;
860                                 return true;
861
862                         case "/help":
863                         case "/?":
864                                 Usage ();
865                                 Environment.Exit (0);
866                                 return true;
867
868                         case "/main":
869                         case "/m":
870                                 if (value == ""){
871                                         Usage ();
872                                         Environment.Exit (1);
873                                 }
874                                 RootContext.MainClass = value;
875                                 return true;
876
877                         case "/nostdlib":
878                         case "/nostdlib+":
879                                 RootContext.StdLib = false;
880                                 return true;
881
882                         case "/nostdlib-":
883                                 RootContext.StdLib = true;
884                                 return true;
885
886                         }
887                         return false;
888                 }
889                 
890                 /// <summary>
891                 ///    Parses the arguments, and drives the compilation
892                 ///    process.
893                 /// </summary>
894                 ///
895                 /// <remarks>
896                 ///    TODO: Mostly structured to debug the compiler
897                 ///    now, needs to be turned into a real driver soon.
898                 /// </remarks>
899                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
900                 static bool MainDriver (string [] args)
901                 {
902                         int i;
903                         bool parsing_options = true;
904                         
905                         references = new ArrayList ();
906                         soft_references = new ArrayList ();
907                         link_paths = new ArrayList ();
908
909                         SetupDefaultDefines ();
910                         
911                         //
912                         // Setup defaults
913                         //
914                         // This is not required because Assembly.Load knows about this
915                         // path.
916                         //
917                         link_paths.Add (GetSystemDir ());
918
919                         int argc = args.Length;
920                         for (i = 0; i < argc; i++){
921                                 string arg = args [i];
922
923                                 if (arg.StartsWith ("@")){
924                                         string [] new_args, extra_args;
925                                         string response_file = arg.Substring (1);
926
927                                         if (response_file_list == null)
928                                                 response_file_list = new Hashtable ();
929                                         
930                                         if (response_file_list.Contains (response_file)){
931                                                 Report.Error (
932                                                         1515, "Response file `" + response_file +
933                                                         "' specified multiple times");
934                                                 Environment.Exit (1);
935                                         }
936                                         
937                                         response_file_list.Add (response_file, response_file);
938                                                     
939                                         extra_args = LoadArgs (response_file);
940                                         if (extra_args == null){
941                                                 Report.Error (2011, "Unable to open response file: " +
942                                                               response_file);
943                                                 return false;
944                                         }
945
946                                         new_args = new string [extra_args.Length + argc];
947                                         args.CopyTo (new_args, 0);
948                                         extra_args.CopyTo (new_args, argc);
949                                         args = new_args;
950                                         argc = new_args.Length;
951                                         continue;
952                                 }
953
954                                 if (parsing_options){
955                                         if (arg == "--"){
956                                                 parsing_options = false;
957                                                 continue;
958                                         }
959                                         
960                                         if (arg.StartsWith ("-")){
961                                                 if (UnixParseOption (arg, ref args, ref i))
962                                                         continue;
963                                         } else {
964                                                 if (arg.StartsWith ("/"))
965                                                         if (CSCParseOption (arg, ref args, ref i))
966                                                                 continue;
967                                         }
968                                 }
969
970                                 CompileFiles (arg, false); 
971                         }
972
973                         if (tokenize)
974                                 return true;
975                         
976                         if (first_source == null){
977                                 Report.Error (2008, "No files to compile were specified");
978                                 return false;
979                         }
980
981                         if (Report.Errors > 0)
982                                 return false;
983                         
984                         if (parse_only)
985                                 return true;
986                         
987                         //
988                         // Load Core Library for default compilation
989                         //
990                         if (RootContext.StdLib)
991                                 references.Insert (0, "mscorlib");
992
993                         if (load_default_config)
994                                 DefineDefaultConfig ();
995
996                         if (Report.Errors > 0){
997                                 return false;
998                         }
999
1000                         //
1001                         // Load assemblies required
1002                         //
1003                         if (timestamps)
1004                                 ShowTime ("Loading references");
1005                         LoadReferences ();
1006                         
1007                         if (timestamps)
1008                                 ShowTime ("   References loaded");
1009                         
1010                         if (Report.Errors > 0){
1011                                 return false;
1012                         }
1013
1014                         //
1015                         // Quick hack
1016                         //
1017                         if (output_file == null){
1018                                 int pos = first_source.LastIndexOf (".");
1019
1020                                 if (pos > 0)
1021                                         output_file = first_source.Substring (0, pos) + target_ext;
1022                                 else
1023                                         output_file = first_source + target_ext;
1024                         }
1025
1026                         string[] debug_args = new string [debug_arglist.Count];
1027                         debug_arglist.CopyTo (debug_args);
1028                         CodeGen.Init (output_file, output_file, want_debugging_support, debug_args);
1029
1030                         TypeManager.AddModule (CodeGen.ModuleBuilder);
1031
1032                         //
1033                         // Before emitting, we need to get the core
1034                         // types emitted from the user defined types
1035                         // or from the system ones.
1036                         //
1037                         if (timestamps)
1038                                 ShowTime ("Initializing Core Types");
1039                         if (!RootContext.StdLib){
1040                                 RootContext.ResolveCore ();
1041                                 if (Report.Errors > 0)
1042                                         return false;
1043                         }
1044                         
1045                         TypeManager.InitCoreTypes ();
1046                         if (timestamps)
1047                                 ShowTime ("   Core Types done");
1048
1049                         //
1050                         // The second pass of the compiler
1051                         //
1052                         if (timestamps)
1053                                 ShowTime ("Resolving tree");
1054                         RootContext.ResolveTree ();
1055                         if (timestamps)
1056                                 ShowTime ("Populate tree");
1057                         if (!RootContext.StdLib)
1058                                 RootContext.BootCorlib_PopulateCoreTypes ();
1059                         RootContext.PopulateTypes ();
1060                         
1061                         TypeManager.InitCodeHelpers ();
1062                                 
1063                         if (Report.Errors > 0){
1064                                 return false;
1065                         }
1066                         
1067                         //
1068                         // The code generator
1069                         //
1070                         if (timestamps)
1071                                 ShowTime ("Emitting code");
1072                         RootContext.EmitCode ();
1073                         if (timestamps)
1074                                 ShowTime ("   done");
1075
1076                         if (Report.Errors > 0){
1077                                 return false;
1078                         }
1079
1080                         if (timestamps)
1081                                 ShowTime ("Closing types");
1082                         
1083                         RootContext.CloseTypes ();
1084
1085                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1086                                 
1087                         if (target == Target.Library || target == Target.Module)
1088                                 k = PEFileKinds.Dll;
1089                         else if (target == Target.Exe)
1090                                 k = PEFileKinds.ConsoleApplication;
1091                         else if (target == Target.WinExe)
1092                                 k = PEFileKinds.WindowApplication;
1093
1094                         if (target == Target.Exe || target == Target.WinExe){
1095                                 MethodInfo ep = RootContext.EntryPoint;
1096
1097                                 if (ep == null){
1098                                         Report.Error (5001, "Program " + output_file +
1099                                                               " does not have an entry point defined");
1100                                         return false;
1101                                 }
1102                                 
1103                                 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
1104                         }
1105
1106                         //
1107                         // Add the resources
1108                         //
1109                         if (resources != null){
1110                                 foreach (string file in resources)
1111                                         CodeGen.AssemblyBuilder.AddResourceFile (file, file);
1112                         }
1113                         
1114                         CodeGen.Save (output_file);
1115                         if (timestamps)
1116                                 ShowTime ("Saved output");
1117
1118                         if (want_debugging_support) {
1119                                 CodeGen.SaveSymbols ();
1120                                 if (timestamps)
1121                                         ShowTime ("Saved symbols");
1122                         }
1123
1124                         if (Report.ExpectedError != 0){
1125                                 Console.WriteLine("Failed to report expected error " + Report.ExpectedError);
1126                                 Environment.Exit (1);
1127                                 return false;
1128                         }
1129
1130                         return (Report.Errors == 0);
1131                 }
1132
1133         }
1134 }