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