2004-12-06 Zoltan Varga <vargaz@freemail.hu>
[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 // (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.Diagnostics;
19         using System.IO;
20         using System.Text;
21         using System.Globalization;
22         using System.Xml;
23         using System.Diagnostics;
24
25         public enum Target {
26                 Library, Exe, Module, WinExe
27         };
28         
29         /// <summary>
30         ///    The compiler driver.
31         /// </summary>
32         public class Driver
33         {
34                 
35                 //
36                 // Assemblies references to be linked.   Initialized with
37                 // mscorlib.dll here.
38                 static ArrayList references;
39
40                 //
41                 // If any of these fail, we ignore the problem.  This is so
42                 // that we can list all the assemblies in Windows and not fail
43                 // if they are missing on Linux.
44                 //
45                 static ArrayList soft_references;
46
47                 //
48                 // Modules to be linked
49                 //
50                 static ArrayList modules;
51
52                 // Lookup paths
53                 static ArrayList link_paths;
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                         try {
180                                 parser.parse ();
181                         } catch (Exception ex) {
182                                 Report.Error(666, "Compilation aborted: " + ex);
183                         } finally {
184                                 input.Close ();
185                         }
186                 }
187                 
188                 static void OtherFlags ()
189                 {
190                         Console.WriteLine (
191                                 "Other flags in the compiler\n" +
192                                 "   --fatal            Makes errors fatal\n" +
193                                 "   --parse            Only parses the source file\n" +
194                                 "   --stacktrace       Shows stack trace at error location\n" +
195                                 "   --timestamp        Displays time stamps of various compiler events\n" +
196                                 "   -2                 Enables experimental C# features\n" +
197                                 "   -v                 Verbose parsing (for debugging the parser)\n" + 
198                                 "   --mcs-debug X      Sets MCS debugging level to X\n");
199                 }
200                 
201                 static void Usage ()
202                 {
203                         Console.WriteLine (
204                                 "Mono C# compiler, (C) 2001 - 2003 Ximian, Inc.\n" +
205                                 "mcs [options] source-files\n" +
206                                 "   --about            About the Mono C# compiler\n" +
207                                 "   -addmodule:MODULE  Adds the module to the generated assembly\n" + 
208                                 "   -checked[+|-]      Set default context to checked\n" +
209                                 "   -codepage:ID       Sets code page to the one in ID\n" +
210                                 "                      (number, `utf8' or `reset')\n" +
211                                 "   -clscheck[+|-]     Disables CLS Compliance verifications" + Environment.NewLine +
212                                 "   -define:S1[;S2]    Defines one or more symbols (short: /d:)\n" +
213                                 "   -debug[+|-]        Generate debugging information\n" + 
214                                 "   -delaysign[+|-]    Only insert the public key into the assembly (no signing)\n" +
215                                 "   -doc:FILE          XML Documentation file to generate\n" + 
216                                 "   -g                 Generate debugging information\n" +
217                                 "   -keycontainer:NAME The key pair container used to strongname the assembly\n" +
218                                 "   -keyfile:FILE      The strongname key file used to strongname the assembly\n" +
219                                 "   -langversion:TEXT  Specifies language version modes: ISO-1 or Default" + Environment.NewLine +
220                                 "   -lib:PATH1,PATH2   Adds the paths to the assembly link path\n" +
221                                 "   -main:class        Specified the class that contains the entry point\n" +
222                                 "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
223                                 "   -nostdlib[+|-]     Does not load core libraries\n" +
224                                 "   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
225                                 "   -out:FNAME         Specifies output file\n" +
226                                 "   -doc:XMLFILE         Generates xml documentation into specified 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 "-v":
661                                 CSharpParser.yacc_verbose_flag++;
662                                 return true;
663
664                         case "--version":
665                                 Version ();
666                                 return true;
667                                 
668                         case "--parse":
669                                 parse_only = true;
670                                 return true;
671                                 
672                         case "--main": case "-m":
673                                 if ((i + 1) >= args.Length){
674                                         Usage ();
675                                         Environment.Exit (1);
676                                 }
677                                 RootContext.MainClass = args [++i];
678                                 return true;
679                                 
680                         case "--unsafe":
681                                 RootContext.Unsafe = true;
682                                 return true;
683                                 
684                         case "/?": case "/h": case "/help":
685                         case "--help":
686                                 Usage ();
687                                 Environment.Exit (0);
688                                 return true;
689                                 
690                         case "--define":
691                                 if ((i + 1) >= args.Length){
692                                         Usage ();
693                                         Environment.Exit (1);
694                                 }
695                                 defines.Add (args [++i]);
696                                 return true;
697
698                         case "--show-counters":
699                                 show_counters = true;
700                                 return true;
701                                 
702                         case "--expect-error": {
703                                 int code = 0;
704                                 
705                                 try {
706                                         code = Int32.Parse (
707                                                 args [++i], NumberStyles.AllowLeadingSign);
708                                         Report.ExpectedError = code;
709                                 } catch {
710                                         Report.Error (-14, "Invalid number specified");
711                                 } 
712                                 return true;
713                         }
714                                 
715                         case "--tokenize": 
716                                 tokenize = true;
717                                 return true;
718                                 
719                         case "-o": 
720                         case "--output":
721                                 if ((i + 1) >= args.Length){
722                                         Usage ();
723                                         Environment.Exit (1);
724                                 }
725                                 SetOutputFile (args [++i]);
726                                 return true;
727                                 
728                         case "--checked":
729                                 RootContext.Checked = true;
730                                 return true;
731                                 
732                         case "--stacktrace":
733                                 Report.Stacktrace = true;
734                                 return true;
735                                 
736                         case "--linkresource":
737                         case "--linkres":
738                                 if ((i + 1) >= args.Length){
739                                         Usage ();
740                                         Report.Error (5, "Missing argument to --linkres"); 
741                                         Environment.Exit (1);
742                                 }
743                                 if (resources == null)
744                                         resources = new ArrayList ();
745                                 
746                                 resources.Add (args [++i]);
747                                 return true;
748                                 
749                         case "--resource":
750                         case "--res":
751                                 if ((i + 1) >= args.Length){
752                                         Usage ();
753                                         Report.Error (5, "Missing argument to --resource"); 
754                                         Environment.Exit (1);
755                                 }
756                                 if (embedded_resources == null)
757                                         embedded_resources = new ArrayList ();
758                                 
759                                 embedded_resources.Add (args [++i]);
760                                 return true;
761                                 
762                         case "--target":
763                                 if ((i + 1) >= args.Length){
764                                         Environment.Exit (1);
765                                         return true;
766                                 }
767                                 
768                                 string type = args [++i];
769                                 switch (type){
770                                 case "library":
771                                         RootContext.Target = Target.Library;
772                                         RootContext.TargetExt = ".dll";
773                                         break;
774                                         
775                                 case "exe":
776                                         RootContext.Target = Target.Exe;
777                                         break;
778                                         
779                                 case "winexe":
780                                         RootContext.Target = Target.WinExe;
781                                         break;
782                                         
783                                 case "module":
784                                         RootContext.Target = Target.Module;
785                                         RootContext.TargetExt = ".dll";
786                                         break;
787                                 default:
788                                         TargetUsage ();
789                                         Environment.Exit (1);
790                                         break;
791                                 }
792                                 return true;
793                                 
794                         case "-r":
795                                 if ((i + 1) >= args.Length){
796                                         Usage ();
797                                         Environment.Exit (1);
798                                 }
799                                 
800                                 references.Add (args [++i]);
801                                 return true;
802                                 
803                         case "-L":
804                                 if ((i + 1) >= args.Length){
805                                         Usage ();       
806                                         Environment.Exit (1);
807                                 }
808                                 link_paths.Add (args [++i]);
809                                 return true;
810                                 
811                         case "--nostdlib":
812                                 RootContext.StdLib = false;
813                                 return true;
814                                 
815                         case "--fatal":
816                                 Report.Fatal = true;
817                                 return true;
818                                 
819                         case "--werror":
820                                 Report.WarningsAreErrors = true;
821                                 TestWarningConflict();
822                                 return true;
823                                 
824                         case "--nowarn":
825                                 if ((i + 1) >= args.Length){
826                                         Usage ();
827                                         Environment.Exit (1);
828                                 }
829                                 int warn = 0;
830                                 
831                                 try {
832                                         warn = Int32.Parse (args [++i]);
833                                 } catch {
834                                         Usage ();
835                                         Environment.Exit (1);
836                                 }
837                                 Report.SetIgnoreWarning (warn);
838                                 return true;
839                                 
840                         case "--wlevel":
841                                 if ((i + 1) >= args.Length){
842                                         Report.Error (
843                                                 1900,
844                                                 "--wlevel requires a value from 0 to 4");
845                                         Environment.Exit (1);
846                                 }
847
848                                 SetWarningLevel (args [++i]);
849                                 return true;
850
851                         case "--mcs-debug":
852                                 if ((i + 1) >= args.Length){
853                                         Report.Error (5, "--mcs-debug requires an argument");
854                                         Environment.Exit (1);
855                                 }
856
857                                 try {
858                                         Report.DebugFlags = Int32.Parse (args [++i]);
859                                 } catch {
860                                         Report.Error (5, "Invalid argument to --mcs-debug");
861                                         Environment.Exit (1);
862                                 }
863                                 return true;
864                                 
865                         case "--about":
866                                 About ();
867                                 return true;
868                                 
869                         case "--recurse":
870                                 if ((i + 1) >= args.Length){
871                                         Report.Error (5, "--recurse requires an argument");
872                                         Environment.Exit (1);
873                                 }
874                                 CompileFiles (args [++i], true); 
875                                 return true;
876                                 
877                         case "--timestamp":
878                                 timestamps = true;
879                                 last_time = first_time = DateTime.Now;
880                                 return true;
881
882                         case "--pause":
883                                 pause = true;
884                                 return true;
885                                 
886                         case "--debug": case "-g":
887                                 want_debugging_support = true;
888                                 return true;
889                                 
890                         case "--noconfig":
891                                 load_default_config = false;
892                                 return true;
893                         }
894
895                         return false;
896                 }
897
898                 //
899                 // Currently it is very basic option parsing, but eventually, this will
900                 // be the complete option parser
901                 //
902                 static bool CSCParseOption (string option, ref string [] args, ref int i)
903                 {
904                         int idx = option.IndexOf (':');
905                         string arg, value;
906
907                         if (idx == -1){
908                                 arg = option;
909                                 value = "";
910                         } else {
911                                 arg = option.Substring (0, idx);
912
913                                 value = option.Substring (idx + 1);
914                         }
915
916                         switch (arg){
917                         case "/nologo":
918                                 return true;
919
920                         case "/t":
921                         case "/target":
922                                 switch (value){
923                                 case "exe":
924                                         RootContext.Target = Target.Exe;
925                                         break;
926
927                                 case "winexe":
928                                         RootContext.Target = Target.WinExe;
929                                         break;
930
931                                 case "library":
932                                         RootContext.Target = Target.Library;
933                                         RootContext.TargetExt = ".dll";
934                                         break;
935
936                                 case "module":
937                                         RootContext.Target = Target.Module;
938                                         RootContext.TargetExt = ".netmodule";
939                                         break;
940
941                                 default:
942                                         TargetUsage ();
943                                         Environment.Exit (1);
944                                         break;
945                                 }
946                                 return true;
947
948                         case "/out":
949                                 if (value == ""){
950                                         Usage ();
951                                         Environment.Exit (1);
952                                 }
953                                 SetOutputFile (value);
954                                 return true;
955
956                         case "/optimize":
957                         case "/optimize+":
958                         case "/optimize-":
959                         case "/incremental":
960                         case "/incremental+":
961                         case "/incremental-":
962                                 // nothing.
963                                 return true;
964
965                         case "/d":
966                         case "/define": {
967                                 string [] defs;
968
969                                 if (value == ""){
970                                         Usage ();
971                                         Environment.Exit (1);
972                                 }
973
974                                 defs = value.Split (new Char [] {';', ','});
975                                 foreach (string d in defs){
976                                         defines.Add (d);
977                                 }
978                                 return true;
979                         }
980
981                         case "/linkres":
982                         case "/linkresource":
983                                 if (value == ""){
984                                         Report.Error (5, arg + " requires an argument");
985                                         Environment.Exit (1);
986                                 }
987                                 if (resources == null)
988                                         resources = new ArrayList ();
989                                 
990                                 resources.Add (value);
991                                 return true;
992                                 
993                         case "/pkg": {
994                                 string packages;
995
996                                 if (value == ""){
997                                         Usage ();
998                                         Environment.Exit (1);
999                                 }
1000                                 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
1001                                 
1002                                 ProcessStartInfo pi = new ProcessStartInfo ();
1003                                 pi.FileName = "pkg-config";
1004                                 pi.RedirectStandardOutput = true;
1005                                 pi.UseShellExecute = false;
1006                                 pi.Arguments = "--libs " + packages;
1007                                 Process p = null;
1008                                 try {
1009                                         p = Process.Start (pi);
1010                                 } catch (Exception e) {
1011                                         Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
1012                                         Environment.Exit (1);
1013                                 }
1014
1015                                 if (p.StandardOutput == null){
1016                                         Report.Warning (-27, "Specified package did not return any information");
1017                                         return true;
1018                                 }
1019                                 string pkgout = p.StandardOutput.ReadToEnd ();
1020                                 p.WaitForExit ();
1021                                 if (p.ExitCode != 0) {
1022                                         Report.Error (-27, "Error running pkg-config. Check the above output.");
1023                                         Environment.Exit (1);
1024                                 }
1025
1026                                 if (pkgout != null){
1027                                         string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
1028                                                 Split (new Char [] { ' ', '\t'});
1029                                         args = AddArgs (args, xargs);
1030                                 }
1031                                 
1032                                 p.Close ();
1033                                 return true;
1034                         }
1035                                 
1036                         case "/res":
1037                         case "/resource":
1038                                 if (value == ""){
1039                                         Report.Error (5, "-resource requires an argument");
1040                                         Environment.Exit (1);
1041                                 }
1042                                 if (embedded_resources == null)
1043                                         embedded_resources = new ArrayList ();
1044                                 
1045                                 if (embedded_resources.Contains (value)) {
1046                                         Report.Error (1508, String.Format ("The resource identifier '{0}' has already been used in this assembly.", value));
1047                                 }
1048                                 else if (value.IndexOf (',') != -1 && embedded_resources.Contains (value.Split (',')[1])) {
1049                                         Report.Error (1508, String.Format ("The resource identifier '{0}' has already been used in this assembly.", value));
1050                                 }
1051                                 else {
1052                                 embedded_resources.Add (value);
1053                                 }
1054                                 return true;
1055                                 
1056                         case "/recurse":
1057                                 if (value == ""){
1058                                         Report.Error (5, "-recurse requires an argument");
1059                                         Environment.Exit (1);
1060                                 }
1061                                 CompileFiles (value, true); 
1062                                 return true;
1063
1064                         case "/r":
1065                         case "/reference": {
1066                                 if (value == ""){
1067                                         Report.Error (5, "-reference requires an argument");
1068                                         Environment.Exit (1);
1069                                 }
1070
1071                                 string [] refs = value.Split (new char [] { ';', ',' });
1072                                 foreach (string r in refs){
1073                                         references.Add (r);
1074                                 }
1075                                 return true;
1076                         }
1077                         case "/addmodule": {
1078                                 if (value == ""){
1079                                         Report.Error (5, arg + " requires an argument");
1080                                         Environment.Exit (1);
1081                                 }
1082
1083                                 string [] refs = value.Split (new char [] { ';', ',' });
1084                                 foreach (string r in refs){
1085                                         modules.Add (r);
1086                                 }
1087                                 return true;
1088                         }
1089                         case "/win32res": {
1090                                 if (value == "") {
1091                                         Report.Error (5, arg + " requires an argument");
1092                                         Environment.Exit (1);
1093                                 }
1094
1095                                 win32ResourceFile = value;
1096                                 return true;
1097                         }
1098                         case "/win32icon": {
1099                                 if (value == "") {
1100                                         Report.Error (5, arg + " requires an argument");
1101                                         Environment.Exit (1);
1102                                 }
1103
1104                                 win32IconFile = value;
1105                                 return true;
1106                         }
1107                         case "/doc": {
1108                                 if (value == ""){
1109                                         Report.Error (2006, arg + " requires an argument");
1110                                         Environment.Exit (1);
1111                                 }
1112                                 RootContext.Documentation = new Documentation (value);
1113                                 return true;
1114                         }
1115                         case "/lib": {
1116                                 string [] libdirs;
1117                                 
1118                                 if (value == ""){
1119                                         Report.Error (5, "/lib requires an argument");
1120                                         Environment.Exit (1);
1121                                 }
1122
1123                                 libdirs = value.Split (new Char [] { ',' });
1124                                 foreach (string dir in libdirs)
1125                                         link_paths.Add (dir);
1126                                 return true;
1127                         }
1128
1129                         case "/debug-":
1130                                 want_debugging_support = false;
1131                                 return true;
1132                                 
1133                         case "/debug":
1134                         case "/debug+":
1135                                 want_debugging_support = true;
1136                                 return true;
1137
1138                         case "/checked":
1139                         case "/checked+":
1140                                 RootContext.Checked = true;
1141                                 return true;
1142
1143                         case "/checked-":
1144                                 RootContext.Checked = false;
1145                                 return true;
1146
1147                         case "/clscheck":
1148                         case "/clscheck+":
1149                                 return true;
1150
1151                         case "/clscheck-":
1152                                 RootContext.VerifyClsCompliance = false;
1153                                 return true;
1154
1155                         case "/unsafe":
1156                         case "/unsafe+":
1157                                 RootContext.Unsafe = true;
1158                                 return true;
1159
1160                         case "/unsafe-":
1161                                 RootContext.Unsafe = false;
1162                                 return true;
1163
1164                         case "/warnaserror":
1165                         case "/warnaserror+":
1166                                 Report.WarningsAreErrors = true;
1167                                 TestWarningConflict();
1168                                 return true;
1169
1170                         case "/warnaserror-":
1171                                 Report.WarningsAreErrors = false;
1172                                 return true;
1173
1174                         case "/warn":
1175                                 SetWarningLevel (value);
1176                                 return true;
1177
1178                         case "/nowarn": {
1179                                 string [] warns;
1180
1181                                 if (value == ""){
1182                                         Report.Error (5, "/nowarn requires an argument");
1183                                         Environment.Exit (1);
1184                                 }
1185                                 
1186                                 warns = value.Split (new Char [] {','});
1187                                 foreach (string wc in warns){
1188                                         try {
1189                                                 int warn = Int32.Parse (wc);
1190                                                 if (warn < 1) {
1191                                                         throw new ArgumentOutOfRangeException("warn");
1192                                                 }
1193                                                 Report.SetIgnoreWarning (warn);
1194                                         } catch {
1195                                                 Report.Error (1904, String.Format("'{0}' is not a valid warning number", wc));
1196                                                 Environment.Exit (1);
1197                                         }
1198                                 }
1199                                 return true;
1200                         }
1201
1202                         case "/noconfig-":
1203                                 load_default_config = true;
1204                                 return true;
1205                                 
1206                         case "/noconfig":
1207                         case "/noconfig+":
1208                                 load_default_config = false;
1209                                 return true;
1210
1211                         case "/help2":
1212                                 OtherFlags ();
1213                                 Environment.Exit(0);
1214                                 return true;
1215                                 
1216                         case "/help":
1217                         case "/?":
1218                                 Usage ();
1219                                 Environment.Exit (0);
1220                                 return true;
1221
1222                         case "/main":
1223                         case "/m":
1224                                 if (value == ""){
1225                                         Report.Error (5, arg + " requires an argument");                                        
1226                                         Environment.Exit (1);
1227                                 }
1228                                 RootContext.MainClass = value;
1229                                 return true;
1230
1231                         case "/nostdlib":
1232                         case "/nostdlib+":
1233                                 RootContext.StdLib = false;
1234                                 return true;
1235
1236                         case "/nostdlib-":
1237                                 RootContext.StdLib = true;
1238                                 return true;
1239
1240                         case "/fullpaths":
1241                                 return true;
1242
1243                         case "/keyfile":
1244                                 if (value == String.Empty) {
1245                                         Report.Error (5, arg + " requires an argument");
1246                                         Environment.Exit (1);
1247                                 }
1248                                 RootContext.StrongNameKeyFile = value;
1249                                 return true;
1250                         case "/keycontainer":
1251                                 if (value == String.Empty) {
1252                                         Report.Error (5, arg + " requires an argument");
1253                                         Environment.Exit (1);
1254                                 }
1255                                 RootContext.StrongNameKeyContainer = value;
1256                                 return true;
1257                         case "/delaysign+":
1258                                 RootContext.StrongNameDelaySign = true;
1259                                 return true;
1260                         case "/delaysign-":
1261                                 RootContext.StrongNameDelaySign = false;
1262                                 return true;
1263
1264                         case "/v2":
1265                         case "/2":
1266                                 Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
1267                                 SetupV2 ();
1268                                 return true;
1269                                 
1270                         case "/langversion":
1271                                 switch (value.ToLower (CultureInfo.InvariantCulture)) {
1272                                         case "iso-1":
1273                                                 RootContext.Version = LanguageVersion.ISO_1;
1274                                                 return true;
1275
1276                                         case "default":
1277                                                 SetupV2 ();
1278                                                 return true;
1279                                 }
1280                                 Report.Error (1617, "Invalid option '{0}' for /langversion; must be ISO-1 or Default", value);
1281                                 Environment.Exit (1);
1282                                 return false;
1283
1284                         case "/codepage":
1285                                 int cp = -1;
1286
1287                                 if (value == "utf8"){
1288                                         encoding = new UTF8Encoding();
1289                                         using_default_encoder = false;
1290                                         return true;
1291                                 }
1292                                 if (value == "reset"){
1293                                         //
1294                                         // 28591 is the code page for ISO-8859-1 encoding.
1295                                         //
1296                                         cp = 28591;
1297                                         using_default_encoder = true;
1298                                 }
1299                                 
1300                                 try {
1301                                         cp = Int32.Parse (value);
1302                                         encoding = Encoding.GetEncoding (cp);
1303                                         using_default_encoder = false;
1304                                 } catch {
1305                                         Report.Error (2016, String.Format("Code page '{0}' is invalid or not installed", cp));
1306                                         Environment.Exit (1);
1307                                 }
1308                                 return true;
1309                         }
1310                         //Report.Error (2007, String.Format ("Unrecognized command-line option: '{0}'", option));
1311                         //Environment.Exit (1);
1312                         return false;
1313                 }
1314                 
1315                 static string [] AddArgs (string [] args, string [] extra_args)
1316                 {
1317                         string [] new_args;
1318
1319                         new_args = new string [extra_args.Length + args.Length];
1320                         args.CopyTo (new_args, 0);
1321                         extra_args.CopyTo (new_args, args.Length);
1322
1323                         return new_args;
1324                 }
1325                 
1326                 /// <summary>
1327                 ///    Parses the arguments, and drives the compilation
1328                 ///    process.
1329                 /// </summary>
1330                 ///
1331                 /// <remarks>
1332                 ///    TODO: Mostly structured to debug the compiler
1333                 ///    now, needs to be turned into a real driver soon.
1334                 /// </remarks>
1335                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1336                 internal static bool MainDriver (string [] args)
1337                 {
1338                         int i;
1339                         bool parsing_options = true;
1340
1341                         Console.WriteLine ("ALPHA SOFTWARE: Mono C# Compiler {0} for Generics",
1342                                            Assembly.GetExecutingAssembly ().GetName ().Version.ToString ());
1343                         try {
1344                                 encoding = Encoding.GetEncoding (28591);
1345                         } catch {
1346                                 Console.WriteLine ("Error: could not load encoding 28591, trying 1252");
1347                                 encoding = Encoding.GetEncoding (1252);
1348                         }
1349                         
1350                         references = new ArrayList ();
1351                         soft_references = new ArrayList ();
1352                         modules = new ArrayList ();
1353                         link_paths = new ArrayList ();
1354
1355                         SetupDefaultDefines ();
1356                         
1357                         //
1358                         // Setup defaults
1359                         //
1360                         // This is not required because Assembly.Load knows about this
1361                         // path.
1362                         //
1363
1364                         for (i = 0; i < args.Length; i++){
1365                                 string arg = args [i];
1366                                 if (arg == "")
1367                                         continue;
1368
1369                                 if (arg.StartsWith ("@")){
1370                                         string [] extra_args;
1371                                         string response_file = arg.Substring (1);
1372
1373                                         if (response_file_list == null)
1374                                                 response_file_list = new Hashtable ();
1375                                         
1376                                         if (response_file_list.Contains (response_file)){
1377                                                 Report.Error (
1378                                                         1515, "Response file `" + response_file +
1379                                                         "' specified multiple times");
1380                                                 Environment.Exit (1);
1381                                         }
1382                                         
1383                                         response_file_list.Add (response_file, response_file);
1384                                                     
1385                                         extra_args = LoadArgs (response_file);
1386                                         if (extra_args == null){
1387                                                 Report.Error (2011, "Unable to open response file: " +
1388                                                               response_file);
1389                                                 return false;
1390                                         }
1391
1392                                         args = AddArgs (args, extra_args);
1393                                         continue;
1394                                 }
1395
1396                                 if (parsing_options){
1397                                         if (arg == "--"){
1398                                                 parsing_options = false;
1399                                                 continue;
1400                                         }
1401                                         
1402                                         if (arg.StartsWith ("-")){
1403                                                 if (UnixParseOption (arg, ref args, ref i))
1404                                                         continue;
1405
1406                                                 // Try a -CSCOPTION
1407                                                 string csc_opt = "/" + arg.Substring (1);
1408                                                 if (CSCParseOption (csc_opt, ref args, ref i))
1409                                                         continue;
1410                                         } else {
1411                                                 if (arg.StartsWith ("/")){
1412                                                         if (CSCParseOption (arg, ref args, ref i))
1413                                                                 continue;
1414                                                 }
1415                                         }
1416                                 }
1417
1418                                 CompileFiles (arg, false); 
1419                         }
1420
1421                         ProcessFiles ();
1422
1423                         if (tokenize)
1424                                 return true;
1425                         
1426                         //
1427                         // If we are an exe, require a source file for the entry point
1428                         //
1429                         if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe){
1430                         if (first_source == null){
1431                                 Report.Error (2008, "No files to compile were specified");
1432                                 return false;
1433                         }
1434
1435                         }
1436
1437                         //
1438                         // If there is nothing to put in the assembly, and we are not a library
1439                         //
1440                         if (first_source == null && embedded_resources == null && resources == null){
1441                                         Report.Error (2008, "No files to compile were specified");
1442                                         return false;
1443                         }
1444
1445                         if (Report.Errors > 0)
1446                                 return false;
1447                         
1448                         if (parse_only)
1449                                 return true;
1450                         
1451                         Tokenizer.Cleanup ();
1452                         
1453                         //
1454                         // Load Core Library for default compilation
1455                         //
1456                         if (RootContext.StdLib)
1457                                 references.Insert (0, "mscorlib");
1458
1459                         if (load_default_config)
1460                                 DefineDefaultConfig ();
1461
1462                         if (Report.Errors > 0){
1463                                 return false;
1464                         }
1465
1466                         //
1467                         // Load assemblies required
1468                         //
1469                         if (timestamps)
1470                                 ShowTime ("Loading references");
1471                         link_paths.Add (GetSystemDir ());
1472                         link_paths.Add (Directory.GetCurrentDirectory ());
1473                         LoadReferences ();
1474                         
1475                         if (timestamps)
1476                                 ShowTime ("   References loaded");
1477                         
1478                         if (Report.Errors > 0){
1479                                 return false;
1480                         }
1481
1482                         //
1483                         // Quick hack
1484                         //
1485                         if (output_file == null){
1486                                 int pos = first_source.LastIndexOf ('.');
1487
1488                                 if (pos > 0)
1489                                         output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
1490                                 else
1491                                         output_file = first_source + RootContext.TargetExt;
1492                         }
1493
1494                         CodeGen.Init (output_file, output_file, want_debugging_support);
1495
1496                         if (RootContext.Target == Target.Module) {
1497                                 PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1498                                 if (module_only == null) {
1499                                         Report.Error (0, new Location (-1), "Cannot use /target:module on this runtime: try the Mono runtime instead.");
1500                                         Environment.Exit (1);
1501                                 }
1502
1503                                 MethodInfo set_method = module_only.GetSetMethod (true);
1504                                 set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
1505                         }
1506
1507                         TypeManager.AddModule (CodeGen.Module.Builder);
1508
1509                         if (modules.Count > 0) {
1510                                 MethodInfo adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
1511                                 if (adder_method == null) {
1512                                         Report.Error (0, new Location (-1), "Cannot use /addmodule on this runtime: Try the Mono runtime instead.");
1513                                         Environment.Exit (1);
1514                                 }
1515
1516                                 foreach (string module in modules)
1517                                         LoadModule (adder_method, module);
1518                         }
1519
1520                         TypeManager.ComputeNamespaces ();
1521                         
1522                         //
1523                         // Before emitting, we need to get the core
1524                         // types emitted from the user defined types
1525                         // or from the system ones.
1526                         //
1527                         if (timestamps)
1528                                 ShowTime ("Initializing Core Types");
1529                         if (!RootContext.StdLib){
1530                                 RootContext.ResolveCore ();
1531                                 if (Report.Errors > 0)
1532                                         return false;
1533                         }
1534                         
1535                         TypeManager.InitCoreTypes ();
1536                         if (timestamps)
1537                                 ShowTime ("   Core Types done");
1538
1539                         //
1540                         // The second pass of the compiler
1541                         //
1542                         if (timestamps)
1543                                 ShowTime ("Resolving tree");
1544                         RootContext.ResolveTree ();
1545
1546                         if (Report.Errors > 0)
1547                                 return false;
1548                         if (timestamps)
1549                                 ShowTime ("Populate tree");
1550                         if (!RootContext.StdLib)
1551                                 RootContext.BootCorlib_PopulateCoreTypes ();
1552                         RootContext.PopulateTypes ();
1553                         RootContext.DefineTypes ();
1554                         
1555                         if (RootContext.Documentation != null &&
1556                                 !RootContext.Documentation.OutputDocComment (
1557                                         output_file))
1558                                 return false;
1559
1560                         TypeManager.InitCodeHelpers ();
1561
1562                         //
1563                         // Verify using aliases now
1564                         //
1565                         Namespace.VerifyUsing ();
1566                         
1567                         if (Report.Errors > 0){
1568                                 return false;
1569                         }
1570                         
1571                         if (RootContext.VerifyClsCompliance) { 
1572                                 CodeGen.Assembly.ResolveClsCompliance ();
1573                                 if (CodeGen.Assembly.IsClsCompliant) {
1574                                 AttributeTester.VerifyModulesClsCompliance ();
1575                                 TypeManager.LoadAllImportedTypes ();
1576                                         AttributeTester.VerifyTopLevelNameClsCompliance ();
1577                                 }
1578                         }
1579                         
1580                         //
1581                         // The code generator
1582                         //
1583                         if (timestamps)
1584                                 ShowTime ("Emitting code");
1585                         ShowTotalTime ("Total so far");
1586                         RootContext.EmitCode ();
1587                         if (timestamps)
1588                                 ShowTime ("   done");
1589
1590                         if (Report.Errors > 0){
1591                                 return false;
1592                         }
1593
1594                         if (timestamps)
1595                                 ShowTime ("Closing types");
1596
1597                         RootContext.CloseTypes ();
1598
1599                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1600                                 
1601                         switch (RootContext.Target) {
1602                         case Target.Library:
1603                         case Target.Module:
1604                                 k = PEFileKinds.Dll; break;
1605                         case Target.Exe:
1606                                 k = PEFileKinds.ConsoleApplication; break;
1607                         case Target.WinExe:
1608                                 k = PEFileKinds.WindowApplication; break;
1609                         }
1610
1611                         if (RootContext.NeedsEntryPoint) {
1612                                 MethodInfo ep = RootContext.EntryPoint;
1613
1614                                 if (ep == null) {
1615                                         if (RootContext.MainClass != null) {
1616                                                 object main_cont = RootContext.Tree.Decls [RootContext.MainClass];
1617                                                 if (main_cont == null) {
1618                                                         Report.Error (1555, output_file, "Could not find '{0}' specified for Main method", RootContext.MainClass); 
1619                                                         return false;
1620                                                 }
1621
1622                                                 if (!(main_cont is ClassOrStruct)) {
1623                                                         Report.Error (1556, output_file, "'{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
1624                                                         return false;
1625                                                 }
1626                                         }
1627
1628                                         if (Report.Errors == 0)
1629                                                 Report.Error (5001, "Program " + output_file +
1630                                                               " does not have an entry point defined");
1631                                         return false;
1632                                 }
1633                                 
1634                                 CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
1635                         } else if (RootContext.MainClass != null) {
1636                                 Report.Error (2017, "Can not specify -main: when building module or library");
1637                         }
1638
1639                         //
1640                         // Add the resources
1641                         //
1642                         if (resources != null){
1643                                 foreach (string spec in resources){
1644                                         string file, res;
1645                                         int cp;
1646                                         
1647                                         cp = spec.IndexOf (',');
1648                                         if (cp != -1){
1649                                                 file = spec.Substring (0, cp);
1650                                                 res = spec.Substring (cp + 1);
1651                                         } else
1652                                                 file = res = spec;
1653
1654                                         CodeGen.Assembly.Builder.AddResourceFile (res, file);
1655                                 }
1656                         }
1657                         
1658                         if (embedded_resources != null){
1659                                 object[] margs = new object [2];
1660                                 Type[] argst = new Type [2];
1661                                 argst [0] = argst [1] = typeof (string);
1662
1663                                 MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod (
1664                                         "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
1665                                         null, CallingConventions.Any, argst, null);
1666                                 
1667                                 if (embed_res == null) {
1668                                         Report.Warning (0, new Location (-1),
1669                                                         "Cannot embed resources on this runtime: try the Mono runtime instead.");
1670                                 } else {
1671                                         foreach (string spec in embedded_resources) {
1672                                                 int cp;
1673
1674                                                 cp = spec.IndexOf (',');
1675                                                 if (cp != -1){
1676                                                         margs [0] = spec.Substring (cp + 1);
1677                                                         margs [1] = spec.Substring (0, cp);
1678                                                 } else {
1679                                                         margs [1] = spec;
1680                                                         margs [0] = Path.GetFileName (spec);
1681                                                 }
1682
1683                                                 if (File.Exists ((string) margs [1]))
1684                                                         embed_res.Invoke (CodeGen.Assembly.Builder, margs);
1685                                                 else {
1686                                                         Report.Error (1566, "Can not find the resource " + margs [1]);
1687                                                 }
1688                                         }
1689                                 }
1690                         }
1691
1692                         //
1693                         // Add Win32 resources
1694                         //
1695
1696                         CodeGen.Assembly.Builder.DefineVersionInfoResource ();
1697
1698                         if (win32ResourceFile != null) {
1699                                 try {
1700                                         CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
1701                                 }
1702                                 catch (ArgumentException) {
1703                                         Report.Warning (0, new Location (-1), "Cannot embed win32 resources on this runtime: try the Mono runtime instead.");
1704                                 }
1705                         }
1706
1707                         if (win32IconFile != null) {
1708                                 MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
1709                                 if (define_icon == null) {
1710                                         Report.Warning (0, new Location (-1), "Cannot embed icon resource on this runtime: try the Mono runtime instead.");
1711                                 }
1712                                 define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
1713                         }
1714
1715                         if (Report.Errors > 0)
1716                                 return false;
1717                         
1718                         CodeGen.Save (output_file);
1719                         if (timestamps) {
1720                                 ShowTime ("Saved output");
1721                                 ShowTotalTime ("Total");
1722                         }
1723
1724                         Timer.ShowTimers ();
1725                         
1726                         if (Report.ExpectedError != 0){
1727                                 if (Report.Errors == 0) {
1728                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1729                                                 "No other errors reported.");
1730                                         
1731                                         Environment.Exit (2);
1732                                 } else {
1733                                         Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
1734                                                 "However, other errors were reported.");
1735                                         
1736                                 Environment.Exit (1);
1737                                 }
1738                                 
1739                                 
1740                                 return false;
1741                         }
1742
1743 #if DEBUGME
1744                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1745                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1746 #endif
1747                         return (Report.Errors == 0);
1748                 }
1749         }
1750
1751         //
1752         // This is the only public entry point
1753         //
1754         public class CompilerCallableEntryPoint : MarshalByRefObject {
1755                 static bool used = false;
1756                 
1757                 public bool InvokeCompiler (string [] args)
1758                 {
1759                         if (used)
1760                                 Reset ();
1761                         bool ok = Driver.MainDriver (args);
1762                         return ok && Report.Errors == 0;
1763                 }
1764
1765                 public void Reset ()
1766                 {
1767                 }
1768         }
1769 }