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