Oops, fix
[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;
235                                         if (assembly.EndsWith (".dll"))
236                                                 full_path = dir + "/" + assembly;
237                                         else
238                                                 full_path = dir + "/" + assembly + ".dll";
239
240                                         try {
241                                                 a = Assembly.LoadFrom (full_path);
242                                                 TypeManager.AddAssembly (a);
243                                                 return;
244                                         } catch (FileNotFoundException ff) {
245                                                 total_log += ff.FusionLog;
246                                                 continue;
247                                         }
248                                 }
249                                 if (!soft) {
250                                         Report.Error (6, "Cannot find assembly `" + assembly + "'" );
251                                         Console.WriteLine ("Log: \n" + total_log);
252                                 }
253                         } catch (BadImageFormatException f) {
254                                 Report.Error(6, "Cannot load assembly (bad file format)" + f.FusionLog);
255                         } catch (FileLoadException f){
256                                 Report.Error(6, "Cannot load assembly " + f.FusionLog);
257                         } catch (ArgumentNullException){
258                                 Report.Error(6, "Cannot load assembly (null argument)");
259                         }
260                 }
261
262                 /// <summary>
263                 ///   Loads all assemblies referenced on the command line
264                 /// </summary>
265                 static public void LoadReferences ()
266                 {
267                         foreach (string r in references)
268                                 LoadAssembly (r, false);
269
270                         foreach (string r in soft_references)
271                                 LoadAssembly (r, true);
272                         
273                         return;
274                 }
275
276                 static void SetupDefaultDefines ()
277                 {
278                         defines = new ArrayList ();
279                         defines.Add ("__MonoCS__");
280                 }
281
282                 static string [] LoadArgs (string file)
283                 {
284                         StreamReader f;
285                         ArrayList args = new ArrayList ();
286                         string line;
287                         try {
288                                 f = new StreamReader (file);
289                         } catch {
290                                 return null;
291                         }
292
293                         while ((line = f.ReadLine ()) != null){
294                                 string [] line_args = line.Split (new char [] { ' ' });
295
296                                 foreach (string arg in line_args)
297                                         args.Add (arg);
298                         }
299
300                         string [] ret_value = new string [args.Count];
301                         args.CopyTo (ret_value, 0);
302
303                         return ret_value;
304                 }
305
306                 //
307                 // Returns the directory where the system assemblies are installed
308                 //
309                 static string GetSystemDir ()
310                 {
311                         Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
312
313                         foreach (Assembly a in assemblies){
314                                 string codebase = a.CodeBase;
315                                 if (codebase.EndsWith ("corlib.dll")){
316                                         return codebase.Substring (0, codebase.LastIndexOf ("/"));
317                                 }
318                         }
319
320                         Report.Error (-15, "Can not compute my system path");
321                         return "";
322                 }
323
324                 //
325                 // Given a path specification, splits the path from the file/pattern
326                 //
327                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
328                 {
329                         int p = spec.LastIndexOf ("/");
330                         if (p != -1){
331                                 //
332                                 // Windows does not like /file.cs, switch that to:
333                                 // "\", "file.cs"
334                                 //
335                                 if (p == 0){
336                                         path = "\\";
337                                         pattern = spec.Substring (1);
338                                 } else {
339                                         path = spec.Substring (0, p);
340                                         pattern = spec.Substring (p + 1);
341                                 }
342                                 return;
343                         }
344
345                         p = spec.LastIndexOf ("\\");
346                         if (p != -1){
347                                 path = spec.Substring (0, p);
348                                 pattern = spec.Substring (p + 1);
349                                 return;
350                         }
351
352                         path = ".";
353                         pattern = spec;
354                 }
355
356                 static void ProcessFile (string f)
357                 {
358                         if (first_source == null)
359                                 first_source = f;
360
361                         if (source_files.Contains (f)){
362                                 Report.Error (
363                                         1516,
364                                         "Source file `" + f + "' specified multiple times");
365                                 Environment.Exit (1);
366                         } else
367                                 source_files.Add (f, f);
368                                         
369                         if (tokenize) {
370                                 tokenize_file (f);
371                         } else {
372                                 parse (f);
373                         }
374                 }
375
376                 static void CompileFiles (string spec, bool recurse)
377                 {
378                         string path, pattern;
379
380                         SplitPathAndPattern (spec, out path, out pattern);
381                         if (pattern.IndexOf ("*") == -1){
382                                 ProcessFile (spec);
383                                 return;
384                         }
385
386                         string [] files = null;
387                         try {
388                                 files = Directory.GetFiles (path, pattern);
389                         } catch (System.IO.DirectoryNotFoundException) {
390                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
391                                 return;
392                         } catch (System.IO.IOException){
393                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
394                                 return;
395                         }
396                         foreach (string f in files) {
397                                 ProcessFile (f);
398                         }
399
400                         if (!recurse)
401                                 return;
402                         
403                         string [] dirs = null;
404
405                         try {
406                                 dirs = Directory.GetDirectories (path);
407                         } catch {
408                         }
409                         
410                         foreach (string d in dirs) {
411                                         
412                                 // Don't include path in this string, as each
413                                 // directory entry already does
414                                 CompileFiles (d + "/" + pattern, true);
415                         }
416                 }
417
418                 static void DefineDefaultConfig ()
419                 {
420                         //
421                         // For now the "default config" is harcoded into the compiler
422                         // we can move this outside later
423                         //
424                         string [] default_config = {
425                                 "System",
426                                 "System.Xml",
427 #if false
428                                 //
429                                 // Is it worth pre-loading all this stuff?
430                                 //
431                                 "Accessibility",
432                                 "System.Configuration.Install",
433                                 "System.Data",
434                                 "System.Design",
435                                 "System.DirectoryServices",
436                                 "System.Drawing.Design",
437                                 "System.Drawing",
438                                 "System.EnterpriseServices",
439                                 "System.Management",
440                                 "System.Messaging",
441                                 "System.Runtime.Remoting",
442                                 "System.Runtime.Serialization.Formatters.Soap",
443                                 "System.Security",
444                                 "System.ServiceProcess",
445                                 "System.Web",
446                                 "System.Web.RegularExpressions",
447                                 "System.Web.Services",
448                                 "System.Windows.Forms"
449 #endif
450                         };
451                         
452                         int p = 0;
453                         foreach (string def in default_config)
454                                 soft_references.Insert (p++, def);
455                 }
456
457                 static void SetOutputFile (string name)
458                 {
459                         output_file = name;
460                         string bname = CodeGen.Basename (output_file);
461                         if (bname.IndexOf (".") == -1)
462                                 output_file += ".exe";
463                 }
464
465                 static void SetWarningLevel (string s)
466                 {
467                         int level = 0;
468
469                         try {
470                                 level = Int32.Parse (s);
471                         } catch {
472                                 Report.Error (
473                                         1900,
474                                         "--wlevel requires an value from 0 to 4");
475                                 Environment.Exit (1);
476                         }
477                         if (level < 0 || level > 4){
478                                 Report.Error (1900, "Warning level must be 0 to 4");
479                                 Environment.Exit (1);
480                         } else
481                                 RootContext.WarningLevel = level;
482                 }
483                 //
484                 // Currently handles the Unix-like command line options, but will be
485                 // deprecated in favor of the CSCParseOption, which will also handle the
486                 // options that start with a dash in the future.
487                 //
488                 static bool UnixParseOption (string arg, ref string [] args, ref int i)
489                 {
490                         switch (arg){
491                         case "-v":
492                                 yacc_verbose = true;
493                                 return true;
494                                 
495                         case "--parse":
496                                 parse_only = true;
497                                 return true;
498                                 
499                         case "--main": case "-m":
500                                 if ((i + 1) >= args.Length){
501                                         Usage ();
502                                         Environment.Exit (1);
503                                 }
504                                 RootContext.MainClass = args [++i];
505                                 return true;
506                                 
507                         case "--unsafe":
508                                 RootContext.Unsafe = true;
509                                 return true;
510                                 
511                         case "/?": case "/h": case "/help":
512                         case "--help":
513                                 Usage ();
514                                 Environment.Exit (0);
515                                 return true;
516                                 
517                         case "--define":
518                                 if ((i + 1) >= args.Length){
519                                         Usage ();
520                                         Environment.Exit (1);
521                                 }
522                                 defines.Add (args [++i]);
523                                 return true;
524                                 
525                         case "--expect-error": {
526                                 int code = 0;
527                                 
528                                 try {
529                                         code = Int32.Parse (
530                                                 args [++i], NumberStyles.AllowLeadingSign);
531                                         Report.ExpectedError = code;
532                                 } catch {
533                                         Report.Error (-14, "Invalid number specified");
534                                 } 
535                                 return true;
536                         }
537                                 
538                         case "--tokenize": 
539                                 tokenize = true;
540                                 return true;
541                                 
542                         case "-o": 
543                         case "--output":
544                                 if ((i + 1) >= args.Length){
545                                         Usage ();
546                                         Environment.Exit (1);
547                                 }
548                                 SetOutputFile (args [++i]);
549                                 return true;
550                                 
551                         case "--checked":
552                                 RootContext.Checked = true;
553                                 return true;
554                                 
555                         case "--stacktrace":
556                                 Report.Stacktrace = true;
557                                 return true;
558                                 
559                         case "--resource":
560                                 if ((i + 1) >= args.Length){
561                                         Usage ();
562                                         Console.WriteLine("Missing argument to --resource"); 
563                                         Environment.Exit (1);
564                                 }
565                                 if (resources == null)
566                                         resources = new ArrayList ();
567                                 
568                                 resources.Add (args [++i]);
569                                 return true;
570                                 
571                         case "--target":
572                                 if ((i + 1) >= args.Length){
573                                         Environment.Exit (1);
574                                         return true;
575                                 }
576                                 
577                                 string type = args [++i];
578                                 switch (type){
579                                 case "library":
580                                         target = Target.Library;
581                                         target_ext = ".dll";
582                                         break;
583                                         
584                                 case "exe":
585                                         target = Target.Exe;
586                                         break;
587                                         
588                                 case "winexe":
589                                         target = Target.WinExe;
590                                         break;
591                                         
592                                 case "module":
593                                         target = Target.Module;
594                                         target_ext = ".dll";
595                                         break;
596                                 default:
597                                         Usage ();
598                                         Environment.Exit (1);
599                                         break;
600                                 }
601                                 return true;
602                                 
603                         case "-r":
604                                 if ((i + 1) >= args.Length){
605                                         Usage ();
606                                         Environment.Exit (1);
607                                 }
608                                 
609                                 references.Add (args [++i]);
610                                 return true;
611                                 
612                         case "-L":
613                                 if ((i + 1) >= args.Length){
614                                         Usage ();       
615                                         Environment.Exit (1);
616                                 }
617                                 link_paths.Add (args [++i]);
618                                 return true;
619                                 
620                         case "--nostdlib":
621                                 RootContext.StdLib = false;
622                                 return true;
623                                 
624                         case "--fatal":
625                                 Report.Fatal = true;
626                                 return true;
627                                 
628                         case "--werror":
629                                 Report.WarningsAreErrors = true;
630                                 return true;
631                                 
632                         case "--nowarn":
633                                 if ((i + 1) >= args.Length){
634                                         Usage ();
635                                         Environment.Exit (1);
636                                 }
637                                 int warn = 0;
638                                 
639                                 try {
640                                         warn = Int32.Parse (args [++i]);
641                                 } catch {
642                                         Usage ();
643                                         Environment.Exit (1);
644                                 }
645                                 Report.SetIgnoreWarning (warn);
646                                 return true;
647                                 
648                         case "--wlevel":
649                                 if ((i + 1) >= args.Length){
650                                         Report.Error (
651                                                 1900,
652                                                 "--wlevel requires an value from 0 to 4");
653                                         Environment.Exit (1);
654                                 }
655
656                                 SetWarningLevel (args [++i]);
657                                 return true;
658                                 
659                         case "--about":
660                                 About ();
661                                 return true;
662                                 
663                         case "--recurse":
664                                 if ((i + 1) >= args.Length){
665                                         Console.WriteLine ("--recurse requires an argument");
666                                         Environment.Exit (1);
667                                 }
668                                 CompileFiles (args [++i], true); 
669                                 return true;
670                                 
671                         case "--timestamp":
672                                 timestamps = true;
673                                 last_time = DateTime.Now;
674                                 debug_arglist.Add ("timestamp");
675                                 return true;
676                                 
677                         case "--debug": case "-g":
678                                 want_debugging_support = true;
679                                 return true;
680                                 
681                         case "--debug-args":
682                                 if ((i + 1) >= args.Length){
683                                         Console.WriteLine ("--debug-args requires an argument");
684                                         Environment.Exit (1);
685                                 }
686                                 char[] sep = { ',' };
687                                 debug_arglist.AddRange (args [++i].Split (sep));
688                                 return true;
689                                 
690                         case "--noconfig":
691                                 load_default_config = false;
692                                 return true;
693                         }
694
695                         return false;
696                 }
697
698                 //
699                 // Currently it is very basic option parsing, but eventually, this will
700                 // be the complete option parser
701                 //
702                 static bool CSCParseOption (string option, ref string [] args, ref int i)
703                 {
704                         int idx = option.IndexOf (":");
705                         string arg, value;
706
707                         if (idx == -1){
708                                 arg = option;
709                                 value = "";
710                         } else {
711                                 arg = option.Substring (0, idx);
712
713                                 value = option.Substring (idx + 1);
714                         }
715
716                         switch (arg){
717                         case "/nologo":
718                                 return true;
719
720                         case "/t":
721                         case "/target":
722                                 switch (value){
723                                 case "exe":
724                                         target = Target.Exe;
725                                         break;
726
727                                 case "winexe":
728                                         target = Target.WinExe;
729                                         break;
730
731                                 case "library":
732                                         target = Target.Library;
733                                         target_ext = ".dll";
734                                         break;
735
736                                 case "module":
737                                         target = Target.Module;
738                                         target_ext = ".dll";
739                                         break;
740
741                                 default:
742                                         Usage ();
743                                         Environment.Exit (1);
744                                         break;
745                                 }
746                                 return true;
747
748                         case "/out":
749                                 if (value == ""){
750                                         Usage ();
751                                         Environment.Exit (1);
752                                 }
753                                 SetOutputFile (value);
754                                 return true;
755
756                         case "/optimize":
757                         case "/optimize+":
758                         case "/optimize-":
759                         case "/incremental":
760                         case "/incremental+":
761                         case "/incremental-":
762                                 // nothing.
763                                 return true;
764
765                         case "/d":
766                         case "/define": {
767                                 string [] defs;
768
769                                 if (value == ""){
770                                         Usage ();
771                                         Environment.Exit (1);
772                                 }
773
774                                 defs = value.Split (new Char [] {';'});
775                                 foreach (string d in defs){
776                                         defines.Add (d);
777                                 }
778                                 return true;
779                         }
780
781                         case "/recurse":
782                                 if (value == ""){
783                                         Console.WriteLine ("/recurse requires an argument");
784                                         Environment.Exit (1);
785                                 }
786                                 CompileFiles (value, true); 
787                                 return true;
788
789                         case "/r":
790                         case "/reference":
791                                 if (value == ""){
792                                         Console.WriteLine ("/recurse requires an argument");
793                                         Environment.Exit (1);
794                                 }
795                                 references.Add (value);
796                                 return true;
797
798                         case "/lib": {
799                                 string [] libdirs;
800                                 
801                                 if (value == ""){
802                                         Usage ();       
803                                         Environment.Exit (1);
804                                 }
805
806                                 libdirs = value.Split (new Char [] { ',' });
807                                 foreach (string dir in libdirs)
808                                         link_paths.Add (dir);
809                                 return true;
810                         }
811                                 
812                         case "/debug":
813                         case "/debug+":
814                                 want_debugging_support = true;
815                                 return true;
816
817                         case "/checked":
818                         case "/checked+":
819                                 RootContext.Checked = true;
820                                 return true;
821
822                         case "/checked-":
823                                 RootContext.Checked = false;
824                                 return true;
825
826                         case "/unsafe":
827                         case "/unsafe+":
828                                 RootContext.Unsafe = true;
829                                 return true;
830
831                         case "/unsafe-":
832                                 RootContext.Unsafe = false;
833                                 return true;
834
835                         case "/warnaserror":
836                         case "/warnaserror+":
837                                 Report.WarningsAreErrors = true;
838                                 return true;
839
840                         case "/warnaserror-":
841                                 Report.WarningsAreErrors = false;
842                                 return true;
843
844                         case "/warn":
845                                 SetWarningLevel (value);
846                                 return true;
847
848                         case "/nowarn": {
849                                 string [] warns;
850
851                                 if (value == ""){
852                                         Usage ();
853                                         Environment.Exit (1);
854                                 }
855                                 
856                                 warns = value.Split (new Char [] {','});
857                                 foreach (string wc in warns){
858                                         int warn = 0;
859                                         
860                                         try {
861                                                 warn = Int32.Parse (wc);
862                                         } catch {
863                                                 Usage ();
864                                                 Environment.Exit (1);
865                                         }
866                                         Report.SetIgnoreWarning (warn);
867                                 }
868                                 return true;
869                         }
870
871                         case "/noconfig":
872                                 load_default_config = false;
873                                 return true;
874
875                         case "/help":
876                         case "/?":
877                                 Usage ();
878                                 Environment.Exit (0);
879                                 return true;
880
881                         case "/main":
882                         case "/m":
883                                 if (value == ""){
884                                         Usage ();
885                                         Environment.Exit (1);
886                                 }
887                                 RootContext.MainClass = value;
888                                 return true;
889
890                         case "/nostdlib":
891                         case "/nostdlib+":
892                                 RootContext.StdLib = false;
893                                 return true;
894
895                         case "/nostdlib-":
896                                 RootContext.StdLib = true;
897                                 return true;
898
899                         }
900                         return false;
901                 }
902                 
903                 /// <summary>
904                 ///    Parses the arguments, and drives the compilation
905                 ///    process.
906                 /// </summary>
907                 ///
908                 /// <remarks>
909                 ///    TODO: Mostly structured to debug the compiler
910                 ///    now, needs to be turned into a real driver soon.
911                 /// </remarks>
912                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
913                 static bool MainDriver (string [] args)
914                 {
915                         int i;
916                         bool parsing_options = true;
917                         
918                         references = new ArrayList ();
919                         soft_references = new ArrayList ();
920                         link_paths = new ArrayList ();
921
922                         SetupDefaultDefines ();
923                         
924                         //
925                         // Setup defaults
926                         //
927                         // This is not required because Assembly.Load knows about this
928                         // path.
929                         //
930
931                         int argc = args.Length;
932                         for (i = 0; i < argc; i++){
933                                 string arg = args [i];
934
935                                 if (arg.StartsWith ("@")){
936                                         string [] new_args, extra_args;
937                                         string response_file = arg.Substring (1);
938
939                                         if (response_file_list == null)
940                                                 response_file_list = new Hashtable ();
941                                         
942                                         if (response_file_list.Contains (response_file)){
943                                                 Report.Error (
944                                                         1515, "Response file `" + response_file +
945                                                         "' specified multiple times");
946                                                 Environment.Exit (1);
947                                         }
948                                         
949                                         response_file_list.Add (response_file, response_file);
950                                                     
951                                         extra_args = LoadArgs (response_file);
952                                         if (extra_args == null){
953                                                 Report.Error (2011, "Unable to open response file: " +
954                                                               response_file);
955                                                 return false;
956                                         }
957
958                                         new_args = new string [extra_args.Length + argc];
959                                         args.CopyTo (new_args, 0);
960                                         extra_args.CopyTo (new_args, argc);
961                                         args = new_args;
962                                         argc = new_args.Length;
963                                         continue;
964                                 }
965
966                                 if (parsing_options){
967                                         if (arg == "--"){
968                                                 parsing_options = false;
969                                                 continue;
970                                         }
971                                         
972                                         if (arg.StartsWith ("-")){
973                                                 if (UnixParseOption (arg, ref args, ref i))
974                                                         continue;
975
976                                                 // Try a -CSCOPTION
977                                                 string csc_opt = "/" + arg.Substring (1);
978                                                 if (CSCParseOption (csc_opt, ref args, ref i))
979                                                         continue;
980                                         } else {
981                                                 if (arg.StartsWith ("/")){
982                                                         if (CSCParseOption (arg, ref args, ref i))
983                                                                 continue;
984                                                 }
985                                         }
986                                 }
987
988                                 CompileFiles (arg, false); 
989                         }
990
991                         if (tokenize)
992                                 return true;
993                         
994                         if (first_source == null){
995                                 Report.Error (2008, "No files to compile were specified");
996                                 return false;
997                         }
998
999                         if (Report.Errors > 0)
1000                                 return false;
1001                         
1002                         if (parse_only)
1003                                 return true;
1004                         
1005                         //
1006                         // Load Core Library for default compilation
1007                         //
1008                         if (RootContext.StdLib)
1009                                 references.Insert (0, "mscorlib");
1010
1011                         if (load_default_config)
1012                                 DefineDefaultConfig ();
1013
1014                         if (Report.Errors > 0){
1015                                 return false;
1016                         }
1017
1018                         //
1019                         // Load assemblies required
1020                         //
1021                         if (timestamps)
1022                                 ShowTime ("Loading references");
1023                         link_paths.Add (GetSystemDir ());
1024                         LoadReferences ();
1025                         
1026                         if (timestamps)
1027                                 ShowTime ("   References loaded");
1028                         
1029                         if (Report.Errors > 0){
1030                                 return false;
1031                         }
1032
1033                         //
1034                         // Quick hack
1035                         //
1036                         if (output_file == null){
1037                                 int pos = first_source.LastIndexOf (".");
1038
1039                                 if (pos > 0)
1040                                         output_file = first_source.Substring (0, pos) + target_ext;
1041                                 else
1042                                         output_file = first_source + target_ext;
1043                         }
1044
1045                         string[] debug_args = new string [debug_arglist.Count];
1046                         debug_arglist.CopyTo (debug_args);
1047                         CodeGen.Init (output_file, output_file, want_debugging_support, debug_args);
1048
1049                         TypeManager.AddModule (CodeGen.ModuleBuilder);
1050
1051                         //
1052                         // Before emitting, we need to get the core
1053                         // types emitted from the user defined types
1054                         // or from the system ones.
1055                         //
1056                         if (timestamps)
1057                                 ShowTime ("Initializing Core Types");
1058                         if (!RootContext.StdLib){
1059                                 RootContext.ResolveCore ();
1060                                 if (Report.Errors > 0)
1061                                         return false;
1062                         }
1063                         
1064                         TypeManager.InitCoreTypes ();
1065                         if (timestamps)
1066                                 ShowTime ("   Core Types done");
1067
1068                         //
1069                         // The second pass of the compiler
1070                         //
1071                         if (timestamps)
1072                                 ShowTime ("Resolving tree");
1073                         RootContext.ResolveTree ();
1074                         if (timestamps)
1075                                 ShowTime ("Populate tree");
1076                         if (!RootContext.StdLib)
1077                                 RootContext.BootCorlib_PopulateCoreTypes ();
1078                         RootContext.PopulateTypes ();
1079                         
1080                         TypeManager.InitCodeHelpers ();
1081                                 
1082                         if (Report.Errors > 0){
1083                                 return false;
1084                         }
1085                         
1086                         //
1087                         // The code generator
1088                         //
1089                         if (timestamps)
1090                                 ShowTime ("Emitting code");
1091                         RootContext.EmitCode ();
1092                         if (timestamps)
1093                                 ShowTime ("   done");
1094
1095                         if (Report.Errors > 0){
1096                                 return false;
1097                         }
1098
1099                         if (timestamps)
1100                                 ShowTime ("Closing types");
1101                         
1102                         RootContext.CloseTypes ();
1103
1104                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1105                                 
1106                         if (target == Target.Library || target == Target.Module)
1107                                 k = PEFileKinds.Dll;
1108                         else if (target == Target.Exe)
1109                                 k = PEFileKinds.ConsoleApplication;
1110                         else if (target == Target.WinExe)
1111                                 k = PEFileKinds.WindowApplication;
1112
1113                         if (target == Target.Exe || target == Target.WinExe){
1114                                 MethodInfo ep = RootContext.EntryPoint;
1115
1116                                 if (ep == null){
1117                                         Report.Error (5001, "Program " + output_file +
1118                                                               " does not have an entry point defined");
1119                                         return false;
1120                                 }
1121                                 
1122                                 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
1123                         }
1124
1125                         //
1126                         // Add the resources
1127                         //
1128                         if (resources != null){
1129                                 foreach (string file in resources)
1130                                         CodeGen.AssemblyBuilder.AddResourceFile (file, file);
1131                         }
1132                         
1133                         CodeGen.Save (output_file);
1134                         if (timestamps)
1135                                 ShowTime ("Saved output");
1136
1137                         if (want_debugging_support) {
1138                                 CodeGen.SaveSymbols ();
1139                                 if (timestamps)
1140                                         ShowTime ("Saved symbols");
1141                         }
1142
1143                         if (Report.ExpectedError != 0){
1144                                 Console.WriteLine("Failed to report expected error " + Report.ExpectedError);
1145                                 Environment.Exit (1);
1146                                 return false;
1147                         }
1148
1149                         return (Report.Errors == 0);
1150                 }
1151
1152         }
1153 }