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