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