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