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