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