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