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