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