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