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