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