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