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