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