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