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