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