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