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