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