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