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