3a5885aa218e724da429435c09ed98d335141ee3
[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, 2002, 2003 Ximian, Inc (http://www.ximian.com)
9 // (C) 2004, 2005 Novell, Inc
10 //
11
12 namespace Mono.CSharp
13 {
14         using System;
15         using System.Reflection;
16         using System.Reflection.Emit;
17         using System.Collections;
18         using System.Collections.Specialized;
19         using System.IO;
20         using System.Text;
21         using System.Globalization;
22         using System.Diagnostics;
23
24         public enum Target {
25                 Library, Exe, Module, WinExe
26         };
27         
28         /// <summary>
29         ///    The compiler driver.
30         /// </summary>
31         public class Driver
32         {
33                 
34                 //
35                 // Assemblies references to be linked.   Initialized with
36                 // mscorlib.dll here.
37                 static ArrayList references;
38
39                 //
40                 // If any of these fail, we ignore the problem.  This is so
41                 // that we can list all the assemblies in Windows and not fail
42                 // if they are missing on Linux.
43                 //
44                 static ArrayList soft_references;
45
46                 // 
47                 // External aliases for assemblies.
48                 //
49                 static Hashtable external_aliases;
50
51                 //
52                 // Modules to be linked
53                 //
54                 static ArrayList modules;
55
56                 // Lookup paths
57                 static ArrayList link_paths;
58
59                 // Whether we want to only run the tokenizer
60                 static bool tokenize = false;
61                 
62                 static string first_source;
63
64                 static bool want_debugging_support = false;
65
66                 static bool parse_only = false;
67                 static bool timestamps = false;
68                 static bool pause = false;
69                 static bool show_counters = false;
70                 
71                 //
72                 // Whether to load the initial config file (what CSC.RSP has by default)
73                 // 
74                 static bool load_default_config = true;
75
76                 //
77                 // A list of resource files
78                 //
79                 static Resources embedded_resources;
80                 static string win32ResourceFile;
81                 static string win32IconFile;
82
83                 //
84                 // An array of the defines from the command line
85                 //
86                 static ArrayList defines;
87
88                 //
89                 // Output file
90                 //
91                 static string output_file = null;
92
93                 //
94                 // Last time we took the time
95                 //
96                 static DateTime last_time, first_time;
97
98                 //
99                 // Encoding.
100                 //
101                 static Encoding encoding;
102
103                 static public void Reset ()
104                 {
105                         want_debugging_support = false;
106                         parse_only = false;
107                         timestamps = false;
108                         pause = false;
109                         show_counters = false;
110                         load_default_config = true;
111                         embedded_resources = null;
112                         win32ResourceFile = win32IconFile = null;
113                         defines = null;
114                         output_file = null;
115                         encoding = null;
116                         first_source = null;
117                 }
118
119                 public static void ShowTime (string msg)
120                 {
121                         if (!timestamps)
122                                 return;
123
124                         DateTime now = DateTime.Now;
125                         TimeSpan span = now - last_time;
126                         last_time = now;
127
128                         Console.WriteLine (
129                                 "[{0:00}:{1:000}] {2}",
130                                 (int) span.TotalSeconds, span.Milliseconds, msg);
131                 }
132
133                 public static void ShowTotalTime (string msg)
134                 {
135                         if (!timestamps)
136                                 return;
137
138                         DateTime now = DateTime.Now;
139                         TimeSpan span = now - first_time;
140                         last_time = now;
141
142                         Console.WriteLine (
143                                 "[{0:00}:{1:000}] {2}",
144                                 (int) span.TotalSeconds, span.Milliseconds, msg);
145                 }              
146                
147                 static void tokenize_file (SourceFile file)
148                 {
149                         Stream input;
150
151                         try {
152                                 input = File.OpenRead (file.Name);
153                         } catch {
154                                 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
155                                 return;
156                         }
157
158                         using (input){
159                                 SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
160                                 Tokenizer lexer = new Tokenizer (reader, file, defines);
161                                 int token, tokens = 0, errors = 0;
162
163                                 while ((token = lexer.token ()) != Token.EOF){
164                                         tokens++;
165                                         if (token == Token.ERROR)
166                                                 errors++;
167                                 }
168                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
169                         }
170                         
171                         return;
172                 }
173
174                 // MonoTODO("Change error code for aborted compilation to something reasonable")]               
175                 static void parse (SourceFile file)
176                 {
177                         CSharpParser parser;
178                         Stream input;
179
180                         try {
181                                 input = File.OpenRead (file.Name);
182                         } catch {
183                                 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
184                                 return;
185                         }
186
187                         SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
188
189                         // Check 'MZ' header
190                         if (reader.Read () == 77 && reader.Read () == 90) {
191                                 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
192                                 input.Close ();
193                                 return;
194                         }
195
196                         reader.Position = 0;
197                         parser = new CSharpParser (reader, file, defines);
198                         parser.ErrorOutput = Report.Stderr;
199                         try {
200                                 parser.parse ();
201                         } catch (Exception ex) {
202                                 Report.Error(666, "Compilation aborted: " + ex);
203                         } finally {
204                                 input.Close ();
205                         }
206                 }
207
208                 static void OtherFlags ()
209                 {
210                         Console.WriteLine (
211                                 "Other flags in the compiler\n" +
212                                 "   --fatal            Makes errors fatal\n" +
213                                 "   --parse            Only parses the source file\n" +
214                                 "   --typetest         Tests the tokenizer's built-in type parser\n" +
215                                 "   --stacktrace       Shows stack trace at error location\n" +
216                                 "   --timestamp        Displays time stamps of various compiler events\n" +
217                                 "   --expect-error X   Expect that error X will be encountered\n" +
218                                 "   -2                 Enables experimental C# features\n" +
219                                 "   -v                 Verbose parsing (for debugging the parser)\n" + 
220                                 "   --mcs-debug X      Sets MCS debugging level to X\n");
221                 }
222                 
223                 static void Usage ()
224                 {
225                         Console.WriteLine (
226                                 "Mono C# compiler, (C) 2001 - 2005 Novell, Inc.\n" +
227                                 "mcs [options] source-files\n" +
228                                 "   --about            About the Mono C# compiler\n" +
229                                 "   -addmodule:MODULE  Adds the module to the generated assembly\n" + 
230                                 "   -checked[+|-]      Set default context to checked\n" +
231                                 "   -codepage:ID       Sets code page to the one in ID (number, utf8, reset)\n" +
232                                 "   -clscheck[+|-]     Disables CLS Compliance verifications" + Environment.NewLine +
233                                 "   -define:S1[;S2]    Defines one or more symbols (short: /d:)\n" +
234                                 "   -debug[+|-], -g    Generate debugging information\n" + 
235                                 "   -delaysign[+|-]    Only insert the public key into the assembly (no signing)\n" +
236                                 "   -doc:FILE          XML Documentation file to generate\n" + 
237                                 "   -keycontainer:NAME The key pair container used to strongname the assembly\n" +
238                                 "   -keyfile:FILE      The strongname key file used to strongname the assembly\n" +
239                                 "   -langversion:TEXT  Specifies language version modes: ISO-1 or Default\n" + 
240                                 "   -lib:PATH1,PATH2   Adds the paths to the assembly link path\n" +
241                                 "   -main:class        Specified the class that contains the entry point\n" +
242                                 "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
243                                 "   -nostdlib[+|-]     Does not load core libraries\n" +
244                                 "   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
245                                 "   -optimize[+|-]     Enables code optimalizations\n" + 
246                                 "   -out:FNAME         Specifies output file\n" +
247                                 "   -pkg:P1[,Pn]       References packages P1..Pn\n" + 
248                                 "   -recurse:SPEC      Recursively compiles the files in SPEC ([dir]/file)\n" + 
249                                 "   -reference:ASS     References the specified assembly (-r:ASS)\n" +
250                                 "   -target:KIND       Specifies the target (KIND is one of: exe, winexe,\n" +
251                                 "                      library, module), (short: /t:)\n" +
252                                 "   -unsafe[+|-]       Allows unsafe code\n" +
253                                 "   -warnaserror[+|-]  Treat warnings as errors\n" +
254                                 "   -warn:LEVEL        Sets warning level (the highest is 4, the default is 2)\n" +
255                                 "   -help2             Show other help flags\n" + 
256                                 "\n" +
257                                 "Resources:\n" +
258                                 "   -linkresource:FILE[,ID] Links FILE as a resource\n" +
259                                 "   -resource:FILE[,ID]     Embed FILE as a resource\n" +
260                                 "   -win32res:FILE          Specifies Win32 resource file (.res)\n" +
261                                 "   -win32icon:FILE         Use this icon for the output\n" +
262                                 "   @file                   Read response file for more options\n\n" +
263                                 "Options can be of the form -option or /option");
264                 }
265
266                 static void TargetUsage ()
267                 {
268                         Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
269                 }
270                 
271                 static void About ()
272                 {
273                         Console.WriteLine (
274                                 "The Mono C# compiler is (C) 2001-2005, Novell, Inc.\n\n" +
275                                 "The compiler source code is released under the terms of the GNU GPL\n\n" +
276
277                                 "For more information on Mono, visit the project Web site\n" +
278                                 "   http://www.go-mono.com\n\n" +
279
280                                 "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath");
281                         Environment.Exit (0);
282                 }
283
284                 public static int counter1, counter2;
285                 
286                 public static int Main (string[] args)
287                 {
288 #if GMCS_SOURCE
289                         RootContext.Version = LanguageVersion.Default;
290 #endif
291                         Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
292
293                         bool ok = MainDriver (args);
294                         
295                         if (ok && Report.Errors == 0) {
296                                 if (Report.Warnings > 0) {
297                                         Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
298                                 }
299                                 if (show_counters){
300                                         Console.WriteLine ("Counter1: " + counter1);
301                                         Console.WriteLine ("Counter2: " + counter2);
302                                 }
303                                 if (pause)
304                                         Console.ReadLine ();
305                                 return 0;
306                         } else {
307                                 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
308                                         Report.Errors, Report.Warnings);
309                                 return 1;
310                         }
311                 }
312
313                 static public void LoadAssembly (string assembly, bool soft)
314                 {
315                         LoadAssembly (assembly, null, soft);
316                 }
317
318                 static void Error6 (string name, string log)
319                 {
320                         if (log != null && log.Length > 0)
321                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
322                         Report.Error (6, "cannot find metadata file `{0}'", name);
323                 }
324
325                 static void Error9 (string type, string filename, string log)
326                 {
327                         if (log != null && log.Length > 0)
328                                 Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
329                         Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
330                 }
331
332                 static void BadAssembly (string filename, string log)
333                 {
334                         MethodInfo adder_method = AssemblyClass.AddModule_Method;
335
336                         if (adder_method != null) {
337                                 AssemblyName an = new AssemblyName ();
338                                 an.Name = ".temp";
339                                 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
340                                 try {
341                                         object m = null;
342                                         try {
343                                                 m = adder_method.Invoke (ab, new object [] { filename });
344                                         } catch (TargetInvocationException ex) {
345                                                 throw ex.InnerException;
346                                         }
347
348                                         if (m != null) {
349                                                 Report.Error (1509, "referenced file `{0}' is not an assembly; try using the '-addmodule' option", filename);
350                                                 return;
351                                         }
352                                 } catch (FileNotFoundException) {
353                                         // did the file get deleted during compilation? who cares? swallow the exception
354                                 } catch (BadImageFormatException) {
355                                         // swallow exception
356                                 } catch (FileLoadException) {
357                                         // swallow exception
358                                 }
359                         }
360                         Error9 ("assembly", filename, log);
361                 }
362
363                 static public void LoadAssembly (string assembly, string alias, bool soft)
364                 {
365                         Assembly a = null;
366                         string total_log = "";
367
368                         try {
369                                 try {
370                                         char[] path_chars = { '/', '\\' };
371
372                                         if (assembly.IndexOfAny (path_chars) != -1) {
373                                                 a = Assembly.LoadFrom (assembly);
374                                         } else {
375                                                 string ass = assembly;
376                                                 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
377                                                         ass = assembly.Substring (0, assembly.Length - 4);
378                                                 a = Assembly.Load (ass);
379                                         }
380                                 } catch (FileNotFoundException) {
381                                         bool err = !soft;
382                                         foreach (string dir in link_paths) {
383                                                 string full_path = Path.Combine (dir, assembly);
384                                                 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
385                                                         full_path += ".dll";
386
387                                                 try {
388                                                         a = Assembly.LoadFrom (full_path);
389                                                         err = false;
390                                                         break;
391                                                 } catch (FileNotFoundException ff) {
392                                                         total_log += ff.FusionLog;
393                                                 }
394                                         }
395                                         if (err) {
396                                                 Error6 (assembly, total_log);
397                                                 return;
398                                         }
399                                 }
400
401                                 // Extern aliased refs require special handling
402                                 if (alias == null)
403                                         RootNamespace.Global.AddAssemblyReference (a);
404                                 else
405                                         RootNamespace.DefineRootNamespace (alias, a);
406
407                         } catch (BadImageFormatException f) {
408                                 // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
409                                 BadAssembly (f.FileName, f.FusionLog);
410                         } catch (FileLoadException f) {
411                                 // ... while .NET 1.1 throws this
412                                 BadAssembly (f.FileName, f.FusionLog);
413                         }
414                 }
415
416                 static public void LoadModule (string module)
417                 {
418                         Module m = null;
419                         string total_log = "";
420
421                         try {
422                                 try {
423                                         m = CodeGen.Assembly.AddModule (module);
424                                 } catch (FileNotFoundException) {
425                                         bool err = true;
426                                         foreach (string dir in link_paths) {
427                                                 string full_path = Path.Combine (dir, module);
428                                                 if (!module.EndsWith (".netmodule"))
429                                                         full_path += ".netmodule";
430
431                                                 try {
432                                                         m = CodeGen.Assembly.AddModule (full_path);
433                                                         err = false;
434                                                         break;
435                                                 } catch (FileNotFoundException ff) {
436                                                         total_log += ff.FusionLog;
437                                                 }
438                                         }
439                                         if (err) {
440                                                 Error6 (module, total_log);
441                                                 return;
442                                         }
443                                 }
444
445                                 RootNamespace.Global.AddModuleReference (m);
446
447                         } catch (BadImageFormatException f) {
448                                 Error9 ("module", f.FileName, f.FusionLog);
449                         } catch (FileLoadException f) {
450                                 Error9 ("module", f.FileName, f.FusionLog);
451                         }
452                 }
453
454                 /// <summary>
455                 ///   Loads all assemblies referenced on the command line
456                 /// </summary>
457                 static public void LoadReferences ()
458                 {
459                         foreach (string r in references)
460                                 LoadAssembly (r, false);
461
462                         foreach (string r in soft_references)
463                                 LoadAssembly (r, true);
464
465                         foreach (DictionaryEntry entry in external_aliases)
466                                 LoadAssembly ((string) entry.Value, (string) entry.Key, false);
467                         
468                         return;
469                 }
470
471                 static void SetupDefaultDefines ()
472                 {
473                         defines = new ArrayList ();
474                         defines.Add ("__MonoCS__");
475                 }
476
477                 static string [] LoadArgs (string file)
478                 {
479                         StreamReader f;
480                         ArrayList args = new ArrayList ();
481                         string line;
482                         try {
483                                 f = new StreamReader (file);
484                         } catch {
485                                 return null;
486                         }
487
488                         StringBuilder sb = new StringBuilder ();
489                         
490                         while ((line = f.ReadLine ()) != null){
491                                 int t = line.Length;
492
493                                 for (int i = 0; i < t; i++){
494                                         char c = line [i];
495                                         
496                                         if (c == '"' || c == '\''){
497                                                 char end = c;
498                                                 
499                                                 for (i++; i < t; i++){
500                                                         c = line [i];
501
502                                                         if (c == end)
503                                                                 break;
504                                                         sb.Append (c);
505                                                 }
506                                         } else if (c == ' '){
507                                                 if (sb.Length > 0){
508                                                         args.Add (sb.ToString ());
509                                                         sb.Length = 0;
510                                                 }
511                                         } else
512                                                 sb.Append (c);
513                                 }
514                                 if (sb.Length > 0){
515                                         args.Add (sb.ToString ());
516                                         sb.Length = 0;
517                                 }
518                         }
519
520                         string [] ret_value = new string [args.Count];
521                         args.CopyTo (ret_value, 0);
522
523                         return ret_value;
524                 }
525
526                 //
527                 // Returns the directory where the system assemblies are installed
528                 //
529                 static string GetSystemDir ()
530                 {
531                         return Path.GetDirectoryName (typeof (object).Assembly.Location);
532                 }
533
534                 //
535                 // Given a path specification, splits the path from the file/pattern
536                 //
537                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
538                 {
539                         int p = spec.LastIndexOf ('/');
540                         if (p != -1){
541                                 //
542                                 // Windows does not like /file.cs, switch that to:
543                                 // "\", "file.cs"
544                                 //
545                                 if (p == 0){
546                                         path = "\\";
547                                         pattern = spec.Substring (1);
548                                 } else {
549                                         path = spec.Substring (0, p);
550                                         pattern = spec.Substring (p + 1);
551                                 }
552                                 return;
553                         }
554
555                         p = spec.LastIndexOf ('\\');
556                         if (p != -1){
557                                 path = spec.Substring (0, p);
558                                 pattern = spec.Substring (p + 1);
559                                 return;
560                         }
561
562                         path = ".";
563                         pattern = spec;
564                 }
565
566                 static void ProcessFile (string f)
567                 {
568                         if (first_source == null)
569                                 first_source = f;
570
571                         Location.AddFile (f);
572                 }
573
574                 static void ProcessFiles ()
575                 {
576                         Location.Initialize ();
577
578                         foreach (SourceFile file in Location.SourceFiles) {
579                                 if (tokenize) {
580                                         tokenize_file (file);
581                                 } else {
582                                         parse (file);
583                                 }
584                         }
585                 }
586
587                 static void CompileFiles (string spec, bool recurse)
588                 {
589                         string path, pattern;
590
591                         SplitPathAndPattern (spec, out path, out pattern);
592                         if (pattern.IndexOf ('*') == -1){
593                                 ProcessFile (spec);
594                                 return;
595                         }
596
597                         string [] files = null;
598                         try {
599                                 files = Directory.GetFiles (path, pattern);
600                         } catch (System.IO.DirectoryNotFoundException) {
601                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
602                                 return;
603                         } catch (System.IO.IOException){
604                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
605                                 return;
606                         }
607                         foreach (string f in files) {
608                                 ProcessFile (f);
609                         }
610
611                         if (!recurse)
612                                 return;
613                         
614                         string [] dirs = null;
615
616                         try {
617                                 dirs = Directory.GetDirectories (path);
618                         } catch {
619                         }
620                         
621                         foreach (string d in dirs) {
622                                         
623                                 // Don't include path in this string, as each
624                                 // directory entry already does
625                                 CompileFiles (d + "/" + pattern, true);
626                         }
627                 }
628
629                 static void DefineDefaultConfig ()
630                 {
631                         //
632                         // For now the "default config" is harcoded into the compiler
633                         // we can move this outside later
634                         //
635                         string [] default_config = {
636                                 "System",
637                                 "System.Xml",
638 #if false
639                                 //
640                                 // Is it worth pre-loading all this stuff?
641                                 //
642                                 "Accessibility",
643                                 "System.Configuration.Install",
644                                 "System.Data",
645                                 "System.Design",
646                                 "System.DirectoryServices",
647                                 "System.Drawing.Design",
648                                 "System.Drawing",
649                                 "System.EnterpriseServices",
650                                 "System.Management",
651                                 "System.Messaging",
652                                 "System.Runtime.Remoting",
653                                 "System.Runtime.Serialization.Formatters.Soap",
654                                 "System.Security",
655                                 "System.ServiceProcess",
656                                 "System.Web",
657                                 "System.Web.RegularExpressions",
658                                 "System.Web.Services",
659                                 "System.Windows.Forms"
660 #endif
661                         };
662                         
663                         int p = 0;
664                         foreach (string def in default_config)
665                                 soft_references.Insert (p++, def);
666                 }
667
668                 public static string OutputFile
669                 {
670                         set {
671                                 output_file = value;
672                         }
673                         get {
674                                 return Path.GetFileName (output_file);
675                         }
676                 }
677
678                 static void SetWarningLevel (string s)
679                 {
680                         int level = -1;
681
682                         try {
683                                 level = Int32.Parse (s);
684                         } catch {
685                         }
686                         if (level < 0 || level > 4){
687                                 Report.Error (1900, "Warning level must be in the range 0-4");
688                                 return;
689                         }
690                         RootContext.WarningLevel = level;
691                 }
692
693                 static void SetupV2 ()
694                 {
695                         RootContext.Version = LanguageVersion.Default;
696                         defines.Add ("__V2__");
697                 }
698                 
699                 static void Version ()
700                 {
701                         string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
702                         Console.WriteLine ("Mono C# compiler version {0}", version);
703                         Environment.Exit (0);
704                 }
705
706                 //
707                 // This is to test the tokenizer internal parser that is used to deambiguate
708                 // '(' type identifier from '(' type others so that we are able to parse
709                 // without introducing reduce/reduce conflicts in the grammar.
710                 // 
711                 static void LambdaTypeParseTest (string fname)
712                 {
713                         bool fail = false;
714
715                         using (FileStream fs = File.OpenRead (fname)){
716                                 StreamReader r = new StreamReader (fs, encoding);
717                                 string line;
718                                 
719                                 while ((line = r.ReadLine ())!= null){
720                                         if (line [0] == '!')
721                                                 continue;
722                                         bool must_pass = line [0] == '+';
723                                         StringReader test = new StringReader (line.Substring (1));
724                                         SeekableStreamReader reader = new SeekableStreamReader (test);
725                                         SourceFile file = new SourceFile (fname, fname, 0);
726                                         
727                                         Tokenizer lexer = new Tokenizer (reader, file, defines);
728                                         bool res = lexer.parse_type_and_parameter ();
729                                         
730                                         Console.WriteLine ("{3} ({1}=={2}): {0}", line.Substring (1), res, must_pass, res == must_pass);
731                                         if (res != must_pass)
732                                                 fail = true;
733                                 }
734                         }
735                         Console.WriteLine ("fail={0}", fail);
736                         Environment.Exit (fail ? 1 : 0);
737                 }
738                 
739                 //
740                 // Currently handles the Unix-like command line options, but will be
741                 // deprecated in favor of the CSCParseOption, which will also handle the
742                 // options that start with a dash in the future.
743                 //
744                 static bool UnixParseOption (string arg, ref string [] args, ref int i)
745                 {
746                         switch (arg){
747                         case "-v":
748                                 CSharpParser.yacc_verbose_flag++;
749                                 return true;
750
751                         case "--version":
752                                 Version ();
753                                 return true;
754                                 
755                         case "--parse":
756                                 parse_only = true;
757                                 return true;
758                                 
759                         case "--main": case "-m":
760                                 Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
761                                 if ((i + 1) >= args.Length){
762                                         Usage ();
763                                         Environment.Exit (1);
764                                 }
765                                 RootContext.MainClass = args [++i];
766                                 return true;
767                                 
768                         case "--unsafe":
769                                 Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
770                                 RootContext.Unsafe = true;
771                                 return true;
772                                 
773                         case "/?": case "/h": case "/help":
774                         case "--help":
775                                 Usage ();
776                                 Environment.Exit (0);
777                                 return true;
778
779                         case "--define":
780                                 Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
781                                 if ((i + 1) >= args.Length){
782                                         Usage ();
783                                         Environment.Exit (1);
784                                 }
785                                 defines.Add (args [++i]);
786                                 return true;
787
788                         case "--show-counters":
789                                 show_counters = true;
790                                 return true;
791                                 
792                         case "--expect-error": {
793                                 int code = 0;
794                                 
795                                 try {
796                                         code = Int32.Parse (
797                                                 args [++i], NumberStyles.AllowLeadingSign);
798                                         Report.ExpectedError = code;
799                                 } catch {
800                                         Report.Error (-14, "Invalid number specified");
801                                 } 
802                                 return true;
803                         }
804                                 
805                         case "--tokenize": 
806                                 tokenize = true;
807                                 return true;
808                                 
809                         case "-o": 
810                         case "--output":
811                                 Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
812                                 if ((i + 1) >= args.Length){
813                                         Usage ();
814                                         Environment.Exit (1);
815                                 }
816                                 OutputFile = args [++i];
817                                 return true;
818
819                         case "--checked":
820                                 Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
821                                 RootContext.Checked = true;
822                                 return true;
823                                 
824                         case "--stacktrace":
825                                 Report.Stacktrace = true;
826                                 return true;
827                                 
828                         case "--linkresource":
829                         case "--linkres":
830                                 Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
831                                 if ((i + 1) >= args.Length){
832                                         Usage ();
833                                         Report.Error (5, "Missing argument to --linkres"); 
834                                         Environment.Exit (1);
835                                 }
836                                 if (embedded_resources == null)
837                                         embedded_resources = new Resources ();
838                                 
839                                 embedded_resources.Add (false, args [++i], args [i]);
840                                 return true;
841                                 
842                         case "--resource":
843                         case "--res":
844                                 Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
845                                 if ((i + 1) >= args.Length){
846                                         Usage ();
847                                         Report.Error (5, "Missing argument to --resource"); 
848                                         Environment.Exit (1);
849                                 }
850                                 if (embedded_resources == null)
851                                         embedded_resources = new Resources ();
852                                 
853                                 embedded_resources.Add (true, args [++i], args [i]);
854                                 return true;
855                                 
856                         case "--target":
857                                 Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
858                                 if ((i + 1) >= args.Length){
859                                         Environment.Exit (1);
860                                         return true;
861                                 }
862                                 
863                                 string type = args [++i];
864                                 switch (type){
865                                 case "library":
866                                         RootContext.Target = Target.Library;
867                                         RootContext.TargetExt = ".dll";
868                                         break;
869                                         
870                                 case "exe":
871                                         RootContext.Target = Target.Exe;
872                                         break;
873                                         
874                                 case "winexe":
875                                         RootContext.Target = Target.WinExe;
876                                         break;
877                                         
878                                 case "module":
879                                         RootContext.Target = Target.Module;
880                                         RootContext.TargetExt = ".dll";
881                                         break;
882                                 default:
883                                         TargetUsage ();
884                                         break;
885                                 }
886                                 return true;
887                                 
888                         case "-r":
889                                 Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
890                                 if ((i + 1) >= args.Length){
891                                         Usage ();
892                                         Environment.Exit (1);
893                                 }
894                                 
895                                 string val = args [++i];
896                                 int idx = val.IndexOf ('=');
897                                 if (idx > -1) {
898                                         string alias = val.Substring (0, idx);
899                                         string assembly = val.Substring (idx + 1);
900                                         AddExternAlias (alias, assembly);
901                                         return true;
902                                 }
903
904                                 references.Add (val);
905                                 return true;
906                                 
907                         case "-L":
908                                 Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
909                                 if ((i + 1) >= args.Length){
910                                         Usage ();       
911                                         Environment.Exit (1);
912                                 }
913                                 link_paths.Add (args [++i]);
914                                 return true;
915                                 
916                         case "--nostdlib":
917                                 Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
918                                 RootContext.StdLib = false;
919                                 return true;
920                                 
921                         case "--fatal":
922                                 Report.Fatal = true;
923                                 return true;
924                                 
925                         case "--werror":
926                                 Report.Warning (-29, 1, "Compatibility: Use -warnaserror: option instead of --werror");
927                                 Report.WarningsAreErrors = true;
928                                 return true;
929
930                         case "--nowarn":
931                                 Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
932                                 if ((i + 1) >= args.Length){
933                                         Usage ();
934                                         Environment.Exit (1);
935                                 }
936                                 int warn = 0;
937                                 
938                                 try {
939                                         warn = Int32.Parse (args [++i]);
940                                 } catch {
941                                         Usage ();
942                                         Environment.Exit (1);
943                                 }
944                                 Report.SetIgnoreWarning (warn);
945                                 return true;
946                                 
947                         case "--wlevel":
948                                 Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
949                                 if ((i + 1) >= args.Length){
950                                         Report.Error (
951                                                 1900,
952                                                 "--wlevel requires a value from 0 to 4");
953                                         Environment.Exit (1);
954                                 }
955
956                                 SetWarningLevel (args [++i]);
957                                 return true;
958
959                         case "--mcs-debug":
960                                 if ((i + 1) >= args.Length){
961                                         Report.Error (5, "--mcs-debug requires an argument");
962                                         Environment.Exit (1);
963                                 }
964
965                                 try {
966                                         Report.DebugFlags = Int32.Parse (args [++i]);
967                                 } catch {
968                                         Report.Error (5, "Invalid argument to --mcs-debug");
969                                         Environment.Exit (1);
970                                 }
971                                 return true;
972                                 
973                         case "--about":
974                                 About ();
975                                 return true;
976                                 
977                         case "--recurse":
978                                 Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
979                                 if ((i + 1) >= args.Length){
980                                         Report.Error (5, "--recurse requires an argument");
981                                         Environment.Exit (1);
982                                 }
983                                 CompileFiles (args [++i], true); 
984                                 return true;
985                                 
986                         case "--timestamp":
987                                 timestamps = true;
988                                 last_time = first_time = DateTime.Now;
989                                 return true;
990
991                         case "--pause":
992                                 pause = true;
993                                 return true;
994                                 
995                         case "--debug": case "-g":
996                                 Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
997                                 want_debugging_support = true;
998                                 return true;
999                                 
1000                         case "--noconfig":
1001                                 Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
1002                                 load_default_config = false;
1003                                 return true;
1004
1005                         case "--typetest":
1006                                 if ((i + 1) >= args.Length){
1007                                         Report.Error (5, "--typetest requires a filename argument");
1008                                         Environment.Exit (1);
1009                                 }
1010                                 LambdaTypeParseTest (args [++i]);
1011                                 return true;
1012                         }
1013
1014                         return false;
1015                 }
1016
1017                 //
1018                 // This parses the -arg and /arg options to the compiler, even if the strings
1019                 // in the following text use "/arg" on the strings.
1020                 //
1021                 static bool CSCParseOption (string option, ref string [] args, ref int i)
1022                 {
1023                         int idx = option.IndexOf (':');
1024                         string arg, value;
1025
1026                         if (idx == -1){
1027                                 arg = option;
1028                                 value = "";
1029                         } else {
1030                                 arg = option.Substring (0, idx);
1031
1032                                 value = option.Substring (idx + 1);
1033                         }
1034
1035                         switch (arg){
1036                         case "/nologo":
1037                                 return true;
1038
1039                         case "/t":
1040                         case "/target":
1041                                 switch (value){
1042                                 case "exe":
1043                                         RootContext.Target = Target.Exe;
1044                                         break;
1045
1046                                 case "winexe":
1047                                         RootContext.Target = Target.WinExe;
1048                                         break;
1049
1050                                 case "library":
1051                                         RootContext.Target = Target.Library;
1052                                         RootContext.TargetExt = ".dll";
1053                                         break;
1054
1055                                 case "module":
1056                                         RootContext.Target = Target.Module;
1057                                         RootContext.TargetExt = ".netmodule";
1058                                         break;
1059
1060                                 default:
1061                                         TargetUsage ();
1062                                         break;
1063                                 }
1064                                 return true;
1065
1066                         case "/out":
1067                                 if (value.Length == 0){
1068                                         Usage ();
1069                                         Environment.Exit (1);
1070                                 }
1071                                 OutputFile = value;
1072                                 return true;
1073
1074                         case "/optimize":
1075                         case "/optimize+":
1076                                 RootContext.Optimize = true;
1077                                 return true;
1078
1079                         case "/optimize-":
1080                                 RootContext.Optimize = false;
1081                                 return true;
1082
1083                         case "/incremental":
1084                         case "/incremental+":
1085                         case "/incremental-":
1086                                 // nothing.
1087                                 return true;
1088
1089                         case "/d":
1090                         case "/define": {
1091                                 string [] defs;
1092
1093                                 if (value.Length == 0){
1094                                         Usage ();
1095                                         Environment.Exit (1);
1096                                 }
1097
1098                                 defs = value.Split (new Char [] {';', ','});
1099                                 foreach (string d in defs){
1100                                         defines.Add (d);
1101                                 }
1102                                 return true;
1103                         }
1104
1105                         case "/bugreport":
1106                                 //
1107                                 // We should collect data, runtime, etc and store in the file specified
1108                                 //
1109                                 Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
1110                                 return true;
1111
1112                         case "/pkg": {
1113                                 string packages;
1114
1115                                 if (value.Length == 0){
1116                                         Usage ();
1117                                         Environment.Exit (1);
1118                                 }
1119                                 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1120                                 
1121                                 ProcessStartInfo pi = new ProcessStartInfo ();
1122                                 pi.FileName = "pkg-config";
1123                                 pi.RedirectStandardOutput = true;
1124                                 pi.UseShellExecute = false;
1125                                 pi.Arguments = "--libs " + packages;
1126                                 Process p = null;
1127                                 try {
1128                                         p = Process.Start (pi);
1129                                 } catch (Exception e) {
1130                                         Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1131                                         Environment.Exit (1);
1132                                 }
1133
1134                                 if (p.StandardOutput == null){
1135                                         Report.Warning (-27, 1, "Specified package did not return any information");
1136                                         return true;
1137                                 }
1138                                 string pkgout = p.StandardOutput.ReadToEnd ();
1139                                 p.WaitForExit ();
1140                                 if (p.ExitCode != 0) {
1141                                         Report.Error (-27, "Error running pkg-config. Check the above output.");
1142                                         Environment.Exit (1);
1143                                 }
1144
1145                                 if (pkgout != null){
1146                                         string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1147                                                 Split (new Char [] { ' ', '\t'});
1148                                         args = AddArgs (args, xargs);
1149                                 }
1150                                 
1151                                 p.Close ();
1152                                 return true;
1153                         }
1154                                 
1155                         case "/linkres":
1156                         case "/linkresource":
1157                         case "/res":
1158                         case "/resource":
1159                                 if (embedded_resources == null)
1160                                         embedded_resources = new Resources ();
1161
1162                                 bool embeded = arg.StartsWith ("/r");
1163                                 string[] s = value.Split (',');
1164                                 switch (s.Length) {
1165                                         case 1:
1166                                                 if (s[0].Length == 0)
1167                                                         goto default;
1168                                                 embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
1169                                                 break;
1170                                         case 2:
1171                                                 embedded_resources.Add (embeded, s [0], s [1]);
1172                                                 break;
1173                                         case 3:
1174                                                 if (s [2] != "public" && s [2] != "private") {
1175                                                         Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
1176                                                         return true;
1177                                                 }
1178                                                 embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
1179                                                 break;
1180                                         default:
1181                                                 Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
1182                                                 break;
1183                                 }
1184
1185                                 return true;
1186                                 
1187                         case "/recurse":
1188                                 if (value.Length == 0){
1189                                         Report.Error (5, "-recurse requires an argument");
1190                                         Environment.Exit (1);
1191                                 }
1192                                 CompileFiles (value, true); 
1193                                 return true;
1194
1195                         case "/r":
1196                         case "/reference": {
1197                                 if (value.Length == 0){
1198                                         Report.Error (5, "-reference requires an argument");
1199                                         Environment.Exit (1);
1200                                 }
1201
1202                                 string [] refs = value.Split (new char [] { ';', ',' });
1203                                 foreach (string r in refs){
1204                                         string val = r;
1205                                         int index = val.IndexOf ('=');
1206                                         if (index > -1) {
1207                                                 string alias = r.Substring (0, index);
1208                                                 string assembly = r.Substring (index + 1);
1209                                                 AddExternAlias (alias, assembly);
1210                                                 return true;
1211                                         }
1212                                         
1213                                         references.Add (val);
1214                                 }
1215                                 return true;
1216                         }
1217                         case "/addmodule": {
1218                                 if (value.Length == 0){
1219                                         Report.Error (5, arg + " requires an argument");
1220                                         Environment.Exit (1);
1221                                 }
1222
1223                                 string [] refs = value.Split (new char [] { ';', ',' });
1224                                 foreach (string r in refs){
1225                                         modules.Add (r);
1226                                 }
1227                                 return true;
1228                         }
1229                         case "/win32res": {
1230                                 if (value.Length == 0) {
1231                                         Report.Error (5, arg + " requires an argument");
1232                                         Environment.Exit (1);
1233                                 }
1234
1235                                 win32ResourceFile = value;
1236                                 return true;
1237                         }
1238                         case "/win32icon": {
1239                                 if (value.Length == 0) {
1240                                         Report.Error (5, arg + " requires an argument");
1241                                         Environment.Exit (1);
1242                                 }
1243
1244                                 win32IconFile = value;
1245                                 return true;
1246                         }
1247                         case "/doc": {
1248                                 if (value.Length == 0){
1249                                         Report.Error (2006, arg + " requires an argument");
1250                                         Environment.Exit (1);
1251                                 }
1252                                 RootContext.Documentation = new Documentation (value);
1253                                 return true;
1254                         }
1255                         case "/lib": {
1256                                 string [] libdirs;
1257                                 
1258                                 if (value.Length == 0){
1259                                         Report.Error (5, "/lib requires an argument");
1260                                         Environment.Exit (1);
1261                                 }
1262
1263                                 libdirs = value.Split (new Char [] { ',' });
1264                                 foreach (string dir in libdirs)
1265                                         link_paths.Add (dir);
1266                                 return true;
1267                         }
1268
1269                         case "/debug-":
1270                                 want_debugging_support = false;
1271                                 return true;
1272                                 
1273                         case "/debug":
1274                         case "/debug+":
1275                                 want_debugging_support = true;
1276                                 return true;
1277
1278                         case "/checked":
1279                         case "/checked+":
1280                                 RootContext.Checked = true;
1281                                 return true;
1282
1283                         case "/checked-":
1284                                 RootContext.Checked = false;
1285                                 return true;
1286
1287                         case "/clscheck":
1288                         case "/clscheck+":
1289                                 return true;
1290
1291                         case "/clscheck-":
1292                                 RootContext.VerifyClsCompliance = false;
1293                                 return true;
1294
1295                         case "/unsafe":
1296                         case "/unsafe+":
1297                                 RootContext.Unsafe = true;
1298                                 return true;
1299
1300                         case "/unsafe-":
1301                                 RootContext.Unsafe = false;
1302                                 return true;
1303
1304                         case "/warnaserror":
1305                         case "/warnaserror+":
1306                                 Report.WarningsAreErrors = true;
1307                                 return true;
1308
1309                         case "/warnaserror-":
1310                                 Report.WarningsAreErrors = false;
1311                                 return true;
1312
1313                         case "/warn":
1314                                 SetWarningLevel (value);
1315                                 return true;
1316
1317                         case "/nowarn": {
1318                                 string [] warns;
1319
1320                                 if (value.Length == 0){
1321                                         Report.Error (5, "/nowarn requires an argument");
1322                                         Environment.Exit (1);
1323                                 }
1324                                 
1325                                 warns = value.Split (new Char [] {','});
1326                                 foreach (string wc in warns){
1327                                         try {
1328                                                 int warn = Int32.Parse (wc);
1329                                                 if (warn < 1) {
1330                                                         throw new ArgumentOutOfRangeException("warn");
1331                                                 }
1332                                                 Report.SetIgnoreWarning (warn);
1333                                         } catch {
1334                                                 Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
1335                                         }
1336                                 }
1337                                 return true;
1338                         }
1339
1340                         case "/noconfig-":
1341                                 load_default_config = true;
1342                                 return true;
1343                                 
1344                         case "/noconfig":
1345                         case "/noconfig+":
1346                                 load_default_config = false;
1347                                 return true;
1348
1349                         case "/help2":
1350                                 OtherFlags ();
1351                                 Environment.Exit(0);
1352                                 return true;
1353                                 
1354                         case "/help":
1355                         case "/?":
1356                                 Usage ();
1357                                 Environment.Exit (0);
1358                                 return true;
1359
1360                         case "/main":
1361                         case "/m":
1362                                 if (value.Length == 0){
1363                                         Report.Error (5, arg + " requires an argument");                                        
1364                                         Environment.Exit (1);
1365                                 }
1366                                 RootContext.MainClass = value;
1367                                 return true;
1368
1369                         case "/nostdlib":
1370                         case "/nostdlib+":
1371                                 RootContext.StdLib = false;
1372                                 return true;
1373
1374                         case "/nostdlib-":
1375                                 RootContext.StdLib = true;
1376                                 return true;
1377
1378                         case "/fullpaths":
1379                                 return true;
1380
1381                         case "/keyfile":
1382                                 if (value == String.Empty) {
1383                                         Report.Error (5, arg + " requires an argument");
1384                                         Environment.Exit (1);
1385                                 }
1386                                 RootContext.StrongNameKeyFile = value;
1387                                 return true;
1388                         case "/keycontainer":
1389                                 if (value == String.Empty) {
1390                                         Report.Error (5, arg + " requires an argument");
1391                                         Environment.Exit (1);
1392                                 }
1393                                 RootContext.StrongNameKeyContainer = value;
1394                                 return true;
1395                         case "/delaysign+":
1396                                 RootContext.StrongNameDelaySign = true;
1397                                 return true;
1398                         case "/delaysign-":
1399                                 RootContext.StrongNameDelaySign = false;
1400                                 return true;
1401
1402                         case "/v2":
1403                         case "/2":
1404                                 Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
1405                                 SetupV2 ();
1406                                 return true;
1407                                 
1408                         case "/langversion":
1409                                 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1410                                 case "iso-1":
1411                                         RootContext.Version = LanguageVersion.ISO_1;
1412                                         return true;
1413                                         
1414                                 case "default":
1415                                         SetupV2 ();
1416                                         return true;
1417                                         
1418                                 case "linq":
1419                                         RootContext.Version = LanguageVersion.LINQ;
1420                                         return true;
1421                                 }
1422                                 Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1' or `Default'", value);
1423                                 return true;
1424
1425                         case "/codepage":
1426                                 switch (value) {
1427                                 case "utf8":
1428                                         encoding = new UTF8Encoding();
1429                                         break;
1430                                 case "reset":
1431                                         encoding = Encoding.Default;
1432                                         break;
1433                                 default:
1434                                         try {
1435                                                 encoding = Encoding.GetEncoding (
1436                                                 Int32.Parse (value));
1437                                         } catch {
1438                                                 Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
1439                                         }
1440                                         break;
1441                                 }
1442                                 return true;
1443                         }
1444
1445                         return false;
1446                 }
1447
1448                 static void Error_WrongOption (string option)
1449                 {
1450                         Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
1451                 }
1452
1453                 static string [] AddArgs (string [] args, string [] extra_args)
1454                 {
1455                         string [] new_args;
1456                         new_args = new string [extra_args.Length + args.Length];
1457
1458                         // if args contains '--' we have to take that into account
1459                         // split args into first half and second half based on '--'
1460                         // and add the extra_args before --
1461                         int split_position = Array.IndexOf (args, "--");
1462                         if (split_position != -1)
1463                         {
1464                                 Array.Copy (args, new_args, split_position);
1465                                 extra_args.CopyTo (new_args, split_position);
1466                                 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
1467                         }
1468                         else
1469                         {
1470                                 args.CopyTo (new_args, 0);
1471                                 extra_args.CopyTo (new_args, args.Length);
1472                         }
1473
1474                         return new_args;
1475                 }
1476
1477                 static void AddExternAlias (string identifier, string assembly)
1478                 {
1479                         if (assembly.Length == 0) {
1480                                 Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
1481                                 return;
1482                         }
1483
1484                         if (!IsExternAliasValid (identifier)) {
1485                                 Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
1486                                 return;
1487                         }
1488                         
1489                         // Could here hashtable throw an exception?
1490                         external_aliases [identifier] = assembly;
1491                 }
1492                 
1493                 static bool IsExternAliasValid (string identifier)
1494                 {
1495                         if (identifier.Length == 0)
1496                                 return false;
1497                         if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
1498                                 return false;
1499
1500                         for (int i = 1; i < identifier.Length; i++) {
1501                                 char c = identifier [i];
1502                                 if (Char.IsLetter (c) || Char.IsDigit (c))
1503                                         continue;
1504
1505                                 UnicodeCategory category = Char.GetUnicodeCategory (c);
1506                                 if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
1507                                                 category != UnicodeCategory.SpacingCombiningMark ||
1508                                                 category != UnicodeCategory.ConnectorPunctuation)
1509                                         return false;
1510                         }
1511                         
1512                         return true;
1513                 }
1514                 
1515                 /// <summary>
1516                 ///    Parses the arguments, and drives the compilation
1517                 ///    process.
1518                 /// </summary>
1519                 ///
1520                 /// <remarks>
1521                 ///    TODO: Mostly structured to debug the compiler
1522                 ///    now, needs to be turned into a real driver soon.
1523                 /// </remarks>
1524                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1525                 internal static bool MainDriver (string [] args)
1526                 {
1527                         int i;
1528                         bool parsing_options = true;
1529
1530                         encoding = Encoding.Default;
1531
1532                         references = new ArrayList ();
1533                         external_aliases = new Hashtable ();
1534                         soft_references = new ArrayList ();
1535                         modules = new ArrayList ();
1536                         link_paths = new ArrayList ();
1537
1538                         SetupDefaultDefines ();
1539                         
1540                         //
1541                         // Setup defaults
1542                         //
1543                         // This is not required because Assembly.Load knows about this
1544                         // path.
1545                         //
1546
1547                         Hashtable response_file_list = null;
1548
1549                         for (i = 0; i < args.Length; i++){
1550                                 string arg = args [i];
1551                                 if (arg.Length == 0)
1552                                         continue;
1553
1554                                 if (arg.StartsWith ("@")){
1555                                         string [] extra_args;
1556                                         string response_file = arg.Substring (1);
1557
1558                                         if (response_file_list == null)
1559                                                 response_file_list = new Hashtable ();
1560                                         
1561                                         if (response_file_list.Contains (response_file)){
1562                                                 Report.Error (
1563                                                         1515, "Response file `" + response_file +
1564                                                         "' specified multiple times");
1565                                                 Environment.Exit (1);
1566                                         }
1567                                         
1568                                         response_file_list.Add (response_file, response_file);
1569                                                     
1570                                         extra_args = LoadArgs (response_file);
1571                                         if (extra_args == null){
1572                                                 Report.Error (2011, "Unable to open response file: " +
1573                                                               response_file);
1574                                                 return false;
1575                                         }
1576
1577                                         args = AddArgs (args, extra_args);
1578                                         continue;
1579                                 }
1580
1581                                 if (parsing_options){
1582                                         if (arg == "--"){
1583                                                 parsing_options = false;
1584                                                 continue;
1585                                         }
1586                                         
1587                                         if (arg.StartsWith ("-")){
1588                                                 if (UnixParseOption (arg, ref args, ref i))
1589                                                         continue;
1590
1591                                                 // Try a -CSCOPTION
1592                                                 string csc_opt = "/" + arg.Substring (1);
1593                                                 if (CSCParseOption (csc_opt, ref args, ref i))
1594                                                         continue;
1595
1596                                                 Error_WrongOption (arg);
1597                                                 return false;
1598                                         } else {
1599                                                 if (arg [0] == '/'){
1600                                                         if (CSCParseOption (arg, ref args, ref i))
1601                                                                 continue;
1602
1603                                                         // Need to skip `/home/test.cs' however /test.cs is considered as error
1604                                                         if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
1605                                                                 Error_WrongOption (arg);
1606                                                                 return false;
1607                                                         }
1608                                                 }
1609                                         }
1610                                 }
1611
1612                                 CompileFiles (arg, false); 
1613                         }
1614
1615                         ProcessFiles ();
1616
1617                         if (tokenize)
1618                                 return true;
1619
1620                         if (RootContext.ToplevelTypes.NamespaceEntry != null)
1621                                 throw new InternalErrorException ("who set it?");
1622
1623                         //
1624                         // If we are an exe, require a source file for the entry point
1625                         //
1626                         if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module){
1627                                 if (first_source == null){
1628                                         Report.Error (2008, "No files to compile were specified");
1629                                         return false;
1630                                 }
1631
1632                         }
1633
1634                         //
1635                         // If there is nothing to put in the assembly, and we are not a library
1636                         //
1637                         if (first_source == null && embedded_resources == null){
1638                                 Report.Error (2008, "No files to compile were specified");
1639                                 return false;
1640                         }
1641
1642                         if (Report.Errors > 0)
1643                                 return false;
1644                         
1645                         if (parse_only)
1646                                 return true;
1647
1648                         //
1649                         // Load Core Library for default compilation
1650                         //
1651                         if (RootContext.StdLib)
1652                                 references.Insert (0, "mscorlib");
1653
1654                         if (load_default_config)
1655                                 DefineDefaultConfig ();
1656
1657                         if (Report.Errors > 0){
1658                                 return false;
1659                         }
1660
1661                         //
1662                         // Load assemblies required
1663                         //
1664                         if (timestamps)
1665                                 ShowTime ("Loading references");
1666                         link_paths.Add (GetSystemDir ());
1667                         link_paths.Add (Directory.GetCurrentDirectory ());
1668                         LoadReferences ();
1669                         
1670                         if (timestamps)
1671                                 ShowTime ("   References loaded");
1672                         
1673                         if (Report.Errors > 0){
1674                                 return false;
1675                         }
1676
1677                         //
1678                         // Quick hack
1679                         //
1680                         if (output_file == null){
1681                                 if (first_source == null){
1682                                         Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
1683                                         return false;
1684                                 }
1685                                         
1686                                 int pos = first_source.LastIndexOf ('.');
1687
1688                                 if (pos > 0)
1689                                         output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1690                                 else
1691                                         output_file = first_source + RootContext.TargetExt;
1692                         }
1693
1694                         if (!CodeGen.Init (output_file, output_file, want_debugging_support))
1695                                 return false;
1696
1697                         if (RootContext.Target == Target.Module) {
1698                                 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1699                                 if (module_only == null) {
1700                                         Report.RuntimeMissingSupport (Location.Null, "/target:module");
1701                                         Environment.Exit (1);
1702                                 }
1703
1704                                 MethodInfo set_method = module_only.GetSetMethod (true);
1705                                 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1706                         }
1707
1708                         RootNamespace.Global.AddModuleReference (CodeGen.Module.Builder);
1709
1710                         if (modules.Count > 0) {
1711                                 foreach (string module in modules)
1712                                         LoadModule (module);
1713                         }
1714                         
1715                         //
1716                         // Before emitting, we need to get the core
1717                         // types emitted from the user defined types
1718                         // or from the system ones.
1719                         //
1720                         if (timestamps)
1721                                 ShowTime ("Initializing Core Types");
1722                         if (!RootContext.StdLib){
1723                                 RootContext.ResolveCore ();
1724                                 if (Report.Errors > 0)
1725                                         return false;
1726                         }
1727                         
1728                         TypeManager.InitCoreTypes ();
1729                         if (timestamps)
1730                                 ShowTime ("   Core Types done");
1731
1732                         CodeGen.Module.Resolve ();
1733
1734                         //
1735                         // The second pass of the compiler
1736                         //
1737                         if (timestamps)
1738                                 ShowTime ("Resolving tree");
1739                         RootContext.ResolveTree ();
1740
1741                         if (Report.Errors > 0)
1742                                 return false;
1743                         if (timestamps)
1744                                 ShowTime ("Populate tree");
1745                         if (!RootContext.StdLib)
1746                                 RootContext.BootCorlib_PopulateCoreTypes ();
1747                         RootContext.PopulateTypes ();
1748
1749                         TypeManager.InitCodeHelpers ();
1750
1751                         RootContext.DefineTypes ();
1752                         
1753                         if (Report.Errors == 0 &&
1754                                 RootContext.Documentation != null &&
1755                                 !RootContext.Documentation.OutputDocComment (
1756                                         output_file))
1757                                 return false;
1758
1759                         //
1760                         // Verify using aliases now
1761                         //
1762                         NamespaceEntry.VerifyAllUsing ();
1763                         
1764                         if (Report.Errors > 0){
1765                                 return false;
1766                         }
1767
1768                         CodeGen.Assembly.Resolve ();
1769                         
1770                         if (RootContext.VerifyClsCompliance) {
1771                                 if (CodeGen.Assembly.IsClsCompliant) {
1772                                         AttributeTester.VerifyModulesClsCompliance ();
1773                                         TypeManager.LoadAllImportedTypes ();
1774                                 }
1775                         }
1776                         if (Report.Errors > 0)
1777                                 return false;
1778                         
1779                         //
1780                         // The code generator
1781                         //
1782                         if (timestamps)
1783                                 ShowTime ("Emitting code");
1784                         ShowTotalTime ("Total so far");
1785                         RootContext.EmitCode ();
1786                         if (timestamps)
1787                                 ShowTime ("   done");
1788
1789                         if (Report.Errors > 0){
1790                                 return false;
1791                         }
1792
1793                         if (timestamps)
1794                                 ShowTime ("Closing types");
1795
1796                         RootContext.CloseTypes ();
1797
1798                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1799
1800                         switch (RootContext.Target) {
1801                         case Target.Library:
1802                         case Target.Module:
1803                                 k = PEFileKinds.Dll; break;
1804                         case Target.Exe:
1805                                 k = PEFileKinds.ConsoleApplication; break;
1806                         case Target.WinExe:
1807                                 k = PEFileKinds.WindowApplication; break;
1808                         }
1809
1810                         if (RootContext.NeedsEntryPoint) {
1811                                 MethodInfo ep = RootContext.EntryPoint;
1812
1813                                 if (ep == null) {
1814                                         if (RootContext.MainClass != null) {
1815                                                 DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
1816                                                 if (main_cont == null) {
1817                                                         Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass); 
1818                                                         return false;
1819                                                 }
1820
1821                                                 if (!(main_cont is ClassOrStruct)) {
1822                                                         Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1823                                                         return false;
1824                                                 }
1825
1826                                                 Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
1827                                                 return false;
1828                                         }
1829
1830                                         if (Report.Errors == 0)
1831                                                 Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
1832                                                         output_file);
1833                                         return false;
1834                                 }
1835
1836                                 CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
1837                         } else if (RootContext.MainClass != null) {
1838                                 Report.Error (2017, "Cannot specify -main if building a module or library");
1839                         }
1840
1841                         if (embedded_resources != null){
1842                                 if (RootContext.Target == Target.Module) {
1843                                         Report.Error (1507, "Cannot link resource file when building a module");
1844                                         return false;
1845                                 }
1846
1847                                 embedded_resources.Emit ();
1848                         }
1849
1850                         //
1851                         // Add Win32 resources
1852                         //
1853
1854                         CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1855
1856                         if (win32ResourceFile != null) {
1857                                 try {
1858                                         CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1859                                 }
1860                                 catch (ArgumentException) {
1861                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1862                                 }
1863                         }
1864
1865                         if (win32IconFile != null) {
1866                                 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1867                                 if (define_icon == null) {
1868                                         Report.RuntimeMissingSupport (Location.Null, "resource embeding");
1869                                 }
1870                                 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1871                         }
1872
1873                         if (Report.Errors > 0)
1874                                 return false;
1875                         
1876                         CodeGen.Save (output_file);
1877                         if (timestamps) {
1878                                 ShowTime ("Saved output");
1879                                 ShowTotalTime ("Total");
1880                         }
1881
1882                         Timer.ShowTimers ();
1883                         
1884                         if (Report.ExpectedError != 0) {
1885                                 if (Report.Errors == 0) {
1886                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1887                                                 "No other errors reported.");
1888                                         
1889                                         Environment.Exit (2);
1890                                 } else {
1891                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1892                                                 "However, other errors were reported.");
1893                                         
1894                                         Environment.Exit (1);
1895                                 }
1896                                 
1897                                 
1898                                 return false;
1899                         }
1900
1901 #if DEBUGME
1902                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1903                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1904 #endif
1905                         return (Report.Errors == 0);
1906                 }
1907         }
1908
1909         class Resources
1910         {
1911                 interface IResource
1912                 {
1913                         void Emit ();
1914                         string FileName { get; }
1915                 }
1916
1917                 class EmbededResource : IResource
1918                 {
1919                         static MethodInfo embed_res;
1920
1921                         static EmbededResource () {
1922                                 Type[] argst = new Type [] { 
1923                                                                                            typeof (string), typeof (string), typeof (ResourceAttributes)
1924                                                                                    };
1925
1926                                 embed_res = typeof (AssemblyBuilder).GetMethod (
1927                                         "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1928                                         null, CallingConventions.Any, argst, null);
1929                                 
1930                                 if (embed_res == null) {
1931                                         Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
1932                                 }
1933                         }
1934
1935                         readonly object[] args;
1936
1937                         public EmbededResource (string name, string file, bool isPrivate)
1938                         {
1939                                 args = new object [3];
1940                                 args [0] = name;
1941                                 args [1] = file;
1942                                 args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1943                         }
1944
1945                         public void Emit()
1946                         {
1947                                 embed_res.Invoke (CodeGen.Assembly.Builder, args);
1948                         }
1949
1950                         public string FileName {
1951                                 get {
1952                                         return (string)args [1];
1953                                 }
1954                         }
1955                 }
1956
1957                 class LinkedResource : IResource
1958                 {
1959                         readonly string file;
1960                         readonly string name;
1961                         readonly ResourceAttributes attribute;
1962
1963                         public LinkedResource (string name, string file, bool isPrivate)
1964                         {
1965                                 this.name = name;
1966                                 this.file = file;
1967                                 this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
1968                         }
1969
1970                         public void Emit ()
1971                         {
1972                                 CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
1973                         }
1974
1975                         public string FileName {
1976                                 get {
1977                                         return file;
1978                                 }
1979                         }
1980                 }
1981
1982
1983                 IDictionary embedded_resources = new HybridDictionary ();
1984
1985                 public void Add (bool embeded, string file, string name)
1986                 {
1987                         Add (embeded, file, name, false);
1988                 }
1989
1990                 public void Add (bool embeded, string file, string name, bool isPrivate)
1991                 {
1992                         if (embedded_resources.Contains (name)) {
1993                                 Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
1994                                 return;
1995                         }
1996                         IResource r = embeded ? 
1997                                 (IResource) new EmbededResource (name, file, isPrivate) : 
1998                                 new LinkedResource (name, file, isPrivate);
1999
2000                         embedded_resources.Add (name, r);
2001                 }
2002
2003                 public void Emit ()
2004                 {
2005                         foreach (IResource r in embedded_resources.Values) {
2006                                 if (!File.Exists (r.FileName)) {
2007                                         Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
2008                                         continue;
2009                                 }
2010                                 
2011                                 r.Emit ();
2012                         }
2013                 }
2014         }
2015
2016         //
2017         // This is the only public entry point
2018         //
2019         public class CompilerCallableEntryPoint : MarshalByRefObject {
2020                 public static bool InvokeCompiler (string [] args, TextWriter error)
2021                 {
2022                         Report.Stderr = error;
2023                         try {
2024                                 return Driver.MainDriver (args) && Report.Errors == 0;
2025                         }
2026                         finally {
2027                                 Report.Stderr = Console.Error;
2028                                 Reset ();
2029                         }
2030                 }
2031
2032                 public static int[] AllWarningNumbers {
2033                         get {
2034                                 return Report.AllWarnings;
2035                         }
2036                 }
2037                 
2038                 static void Reset ()
2039                 {
2040                         Driver.Reset ();
2041                         Location.Reset ();
2042                         RootContext.Reset ();
2043                         Report.Reset ();
2044                         TypeManager.Reset ();
2045                         TypeHandle.Reset ();
2046                         RootNamespace.Reset ();
2047                         NamespaceEntry.Reset ();
2048                         CodeGen.Reset ();
2049                         Attribute.Reset ();
2050                         AttributeTester.Reset ();
2051                 }
2052         }
2053 }