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