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