2003-12-13 Martin Baulig <martin@ximian.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 //
10
11 namespace Mono.CSharp
12 {
13         using System;
14         using System.Reflection;
15         using System.Reflection.Emit;
16         using System.Collections;
17         using System.IO;
18         using System.Text;
19         using System.Globalization;
20         using Mono.Languages;
21
22         enum Target {
23                 Library, Exe, Module, WinExe
24         };
25         
26         /// <summary>
27         ///    The compiler driver.
28         /// </summary>
29         public class Driver
30         {
31                 
32                 //
33                 // Assemblies references to be linked.   Initialized with
34                 // mscorlib.dll here.
35                 static ArrayList references;
36
37                 //
38                 // If any of these fail, we ignore the problem.  This is so
39                 // that we can list all the assemblies in Windows and not fail
40                 // if they are missing on Linux.
41                 //
42                 static ArrayList soft_references;
43
44                 // Lookup paths
45                 static ArrayList link_paths;
46
47                 // Whether we want Yacc to output its progress
48                 static bool yacc_verbose = false;
49
50                 // Whether we want to only run the tokenizer
51                 static bool tokenize = false;
52                 
53                 static string first_source;
54
55                 static Target target = Target.Exe;
56                 static string target_ext = ".exe";
57
58                 static bool want_debugging_support = false;
59
60                 static bool parse_only = false;
61                 static bool timestamps = false;
62                 static bool pause = false;
63                 static bool show_counters = false;
64                 public static bool parser_verbose = false;
65                 
66                 //
67                 // Whether to load the initial config file (what CSC.RSP has by default)
68                 // 
69                 static bool load_default_config = true;
70
71                 static Hashtable response_file_list;
72
73                 //
74                 // A list of resource files
75                 //
76                 static ArrayList resources;
77                 static ArrayList embedded_resources;
78                 
79                 //
80                 // An array of the defines from the command line
81                 //
82                 static ArrayList defines;
83
84                 //
85                 // Output file
86                 //
87                 static string output_file = null;
88
89                 //
90                 // Last time we took the time
91                 //
92                 static DateTime last_time, first_time;
93
94                 //
95                 // Encoding: ISO-Latin1 is 28591
96                 //
97                 static Encoding encoding;
98
99                 //
100                 // Whether the user has specified a different encoder manually
101                 //
102                 static bool using_default_encoder = true;
103                 
104                 public static void ShowTime (string msg)
105                 {
106                         if (!timestamps)
107                                 return;
108
109                         DateTime now = DateTime.Now;
110                         TimeSpan span = now - last_time;
111                         last_time = now;
112
113                         Console.WriteLine (
114                                 "[{0:00}:{1:000}] {2}",
115                                 (int) span.TotalSeconds, span.Milliseconds, msg);
116                 }
117
118                 public static void ShowTotalTime (string msg)
119                 {
120                         if (!timestamps)
121                                 return;
122
123                         DateTime now = DateTime.Now;
124                         TimeSpan span = now - first_time;
125                         last_time = now;
126
127                         Console.WriteLine (
128                                 "[{0:00}:{1:000}] {2}",
129                                 (int) span.TotalSeconds, span.Milliseconds, msg);
130                 }              
131                
132                 static void tokenize_file (SourceFile file)
133                 {
134                         Stream input;
135
136                         try {
137                                 input = File.OpenRead (file.Name);
138                         } catch {
139                                 Report.Error (2001, "Source file '" + file.Name + "' could not be opened");
140                                 return;
141                         }
142
143                         using (input){
144                                 SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder);
145                                 Tokenizer lexer = new Tokenizer (reader, file, defines);
146                                 int token, tokens = 0, errors = 0;
147
148                                 while ((token = lexer.token ()) != Token.EOF){
149                                         Location l = lexer.Location;
150                                         tokens++;
151                                         if (token == Token.ERROR)
152                                                 errors++;
153                                 }
154                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
155                         }
156                         
157                         return;
158                 }
159
160                 // MonoTODO("Change error code for aborted compilation to something reasonable")]               
161                 static void parse (SourceFile file)
162                 {
163                         CSharpParser parser;
164                         Stream input;
165
166                         try {
167                                 input = File.OpenRead (file.Name);
168                         } catch {
169                                 Report.Error (2001, "Source file '" + file.Name + "' could not be opened");
170                                 return;
171                         }
172
173                         SeekableStreamReader reader = new SeekableStreamReader (input, encoding, using_default_encoder);
174                                 
175                         parser = new CSharpParser (reader, file, defines);
176                         parser.yacc_verbose = yacc_verbose;
177                         try {
178                                 parser.parse ();
179                         } catch (Exception ex) {
180                                 Report.Error(666, "Compilation aborted: " + ex);
181                         } finally {
182                                 input.Close ();
183                         }
184                 }
185                 
186                 static void Usage ()
187                 {
188                         Console.WriteLine (
189                                 "Mono C# compiler, (C) 2001 - 2003 Ximian, Inc.\n" +
190                                 "mcs [options] source-files\n" +
191                                 "   --about            About the Mono C# compiler\n" +
192                                 "   -checked[+|-]      Set default context to checked\n" +
193                                 "   -codepage:ID       Sets code page to the one in ID\n" +
194                                 "                      (number, `utf8' or `reset')\n" +
195                                 "   -define:S1[;S2]    Defines one or more symbols (short: /d:)\n" +
196                                 "   -debug[+-]         Generate debugging information\n" + 
197                                 "   -doc:FILE          XML Documentation file to generate\n" + 
198                                 "   -g                 Generate debugging information\n" +
199                                 "   --fatal            Makes errors fatal\n" +
200                                 "   -lib:PATH1,PATH2   Adds the paths to the assembly link path\n" +
201                                 "   -main:class        Specified the class that contains the entry point\n" +
202                                 "   -noconfig[+|-]     Disables implicit references to assemblies\n" +
203                                 "   -nostdlib[+|-]     Does not load core libraries\n" +
204                                 "   -nowarn:W1[,W2]    Disables one or more warnings\n" + 
205                                 "   -out:FNAME         Specifies output file\n" +
206                                 "   --parse            Only parses the source file\n" +
207                                 "   --expect-error X   Expect that error X will be encountered\n" +
208                                 "   -recurse:SPEC      Recursively compiles the files in SPEC ([dir]/file)\n" + 
209                                 "   -reference:ASS     References the specified assembly (-r:ASS)\n" +
210                                 "   --stacktrace       Shows stack trace at error location\n" +
211                                 "   -target:KIND       Specifies the target (KIND is one of: exe, winexe,\n" +
212                                 "                      library, module), (short: /t:)\n" +
213                                 "   --timestamp        Displays time stamps of various compiler events\n" +
214                                 "   -unsafe[+|-]       Allows unsafe code\n" +
215                                 "   -warnaserror[+|-]  Treat warnings as errors\n" +
216                                 "   -warn:LEVEL        Sets warning level (the highest is 4, the default is 2)\n" +
217                                 "   -v                 Verbose parsing (for debugging the parser)\n" +
218                                 "   -2                 Enables experimental C# features\n" +
219                                 "\n" +
220                                 "Resources:\n" +
221                                 "   -linkresource:FILE[,ID] Links FILE as a resource\n" +
222                                 "   -resource:FILE[,ID]     Embed FILE as a resource\n" +
223                                 "   --mcs-debug X      Sets MCS debugging level to X\n" +
224                                 "   @file              Read response file for more options\n\n" +
225                                 "Options can be of the form -option or /option");
226                 }
227
228                 static void TargetUsage ()
229                 {
230                         Report.Error (2019, "Valid options for -target: are exe, winexe, library or module");
231                 }
232                 
233                 static void About ()
234                 {
235                         Console.WriteLine (
236                                 "The Mono C# compiler is (C) 2001, 2002, 2003 Ximian, Inc.\n\n" +
237                                 "The compiler source code is released under the terms of the GNU GPL\n\n" +
238
239                                 "For more information on Mono, visit the project Web site\n" +
240                                 "   http://www.go-mono.com\n\n" +
241
242                                 "The compiler was written by Miguel de Icaza, Ravi Pratap and Martin Baulig");
243                         Environment.Exit (0);
244                 }
245
246                 public static int counter1, counter2;
247                 
248                 public static int Main (string[] args)
249                 {
250                         bool ok = MainDriver (args);
251                         
252                         if (ok && Report.Errors == 0) {
253                                 Console.Write("Compilation succeeded");
254                                 if (Report.Warnings > 0) {
255                                         Console.Write(" - {0} warning(s)", Report.Warnings);
256                                 }
257                                 Console.WriteLine();
258                                 if (show_counters){
259                                         Console.WriteLine ("Counter1: " + counter1);
260                                         Console.WriteLine ("Counter2: " + counter2);
261                                 }
262                                 if (pause)
263                                         Console.ReadLine ();
264                                 return 0;
265                         } else {
266                                 Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
267                                         Report.Errors, Report.Warnings);
268                                 return 1;
269                         }
270                 }
271
272                 static public void LoadAssembly (string assembly, bool soft)
273                 {
274                         Assembly a;
275                         string total_log = "";
276
277                         try {
278                                 char[] path_chars = { '/', '\\', '.' };
279
280                                 if (assembly.IndexOfAny (path_chars) != -1) {
281                                         a = Assembly.LoadFrom (assembly);
282                                 } else {
283                                         a = Assembly.Load (assembly);
284                                 }
285                                 TypeManager.AddAssembly (a);
286
287                         } catch (FileNotFoundException){
288                                 foreach (string dir in link_paths){
289                                         string full_path = Path.Combine (dir, assembly);
290                                         if (!assembly.EndsWith (".dll"))
291                                                 full_path += ".dll";
292
293                                         try {
294                                                 a = Assembly.LoadFrom (full_path);
295                                                 TypeManager.AddAssembly (a);
296                                                 return;
297                                         } catch (FileNotFoundException ff) {
298                                                 total_log += ff.FusionLog;
299                                                 continue;
300                                         }
301                                 }
302                                 if (!soft) {
303                                         Report.Error (6, "Cannot find assembly `" + assembly + "'" );
304                                         Console.WriteLine ("Log: \n" + total_log);
305                                 }
306                         } catch (BadImageFormatException f) {
307                                 Report.Error(6, "Cannot load assembly (bad file format)" + f.FusionLog);
308                         } catch (FileLoadException f){
309                                 Report.Error(6, "Cannot load assembly " + f.FusionLog);
310                         } catch (ArgumentNullException){
311                                 Report.Error(6, "Cannot load assembly (null argument)");
312                         }
313                 }
314
315                 /// <summary>
316                 ///   Loads all assemblies referenced on the command line
317                 /// </summary>
318                 static public void LoadReferences ()
319                 {
320                         foreach (string r in references)
321                                 LoadAssembly (r, false);
322
323                         foreach (string r in soft_references)
324                                 LoadAssembly (r, true);
325                         
326                         return;
327                 }
328
329                 static void SetupDefaultDefines ()
330                 {
331                         defines = new ArrayList ();
332                         defines.Add ("__MonoCS__");
333                 }
334
335                 static string [] LoadArgs (string file)
336                 {
337                         StreamReader f;
338                         ArrayList args = new ArrayList ();
339                         string line;
340                         try {
341                                 f = new StreamReader (file);
342                         } catch {
343                                 return null;
344                         }
345
346                         StringBuilder sb = new StringBuilder ();
347                         
348                         while ((line = f.ReadLine ()) != null){
349                                 int t = line.Length;
350
351                                 for (int i = 0; i < t; i++){
352                                         char c = line [i];
353                                         
354                                         if (c == '"' || c == '\''){
355                                                 char end = c;
356                                                 
357                                                 for (i++; i < t; i++){
358                                                         c = line [i];
359
360                                                         if (c == end)
361                                                                 break;
362                                                         sb.Append (c);
363                                                 }
364                                         } else if (c == ' '){
365                                                 if (sb.Length > 0){
366                                                         args.Add (sb.ToString ());
367                                                         sb.Length = 0;
368                                                 }
369                                         } else
370                                                 sb.Append (c);
371                                 }
372                                 if (sb.Length > 0){
373                                         args.Add (sb.ToString ());
374                                         sb.Length = 0;
375                                 }
376                         }
377
378                         string [] ret_value = new string [args.Count];
379                         args.CopyTo (ret_value, 0);
380
381                         return ret_value;
382                 }
383
384                 //
385                 // Returns the directory where the system assemblies are installed
386                 //
387                 static string GetSystemDir ()
388                 {
389                         Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
390
391                         foreach (Assembly a in assemblies){
392                                 string codebase = a.Location;
393                                 string fn = System.IO.Path.GetFileName (codebase);
394                                 if (fn == "corlib.dll" || fn == "mscorlib.dll"){
395                                         return codebase.Substring (0, codebase.LastIndexOf (System.IO.Path.DirectorySeparatorChar));
396                                 }
397                         }
398
399                         Report.Error (-15, "Can not compute my system path");
400                         return "";
401                 }
402
403                 //
404                 // Given a path specification, splits the path from the file/pattern
405                 //
406                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
407                 {
408                         int p = spec.LastIndexOf ('/');
409                         if (p != -1){
410                                 //
411                                 // Windows does not like /file.cs, switch that to:
412                                 // "\", "file.cs"
413                                 //
414                                 if (p == 0){
415                                         path = "\\";
416                                         pattern = spec.Substring (1);
417                                 } else {
418                                         path = spec.Substring (0, p);
419                                         pattern = spec.Substring (p + 1);
420                                 }
421                                 return;
422                         }
423
424                         p = spec.LastIndexOf ('\\');
425                         if (p != -1){
426                                 path = spec.Substring (0, p);
427                                 pattern = spec.Substring (p + 1);
428                                 return;
429                         }
430
431                         path = ".";
432                         pattern = spec;
433                 }
434
435                 static void ProcessFile (string f)
436                 {
437                         if (first_source == null)
438                                 first_source = f;
439
440                         Location.AddFile (f);
441                 }
442
443                 static void ProcessFiles ()
444                 {
445                         Location.Initialize ();
446
447                         foreach (SourceFile file in Location.SourceFiles) {
448                                 if (tokenize) {
449                                         tokenize_file (file);
450                                 } else {
451                                         parse (file);
452                                 }
453                         }
454                 }
455
456                 static void CompileFiles (string spec, bool recurse)
457                 {
458                         string path, pattern;
459
460                         SplitPathAndPattern (spec, out path, out pattern);
461                         if (pattern.IndexOf ('*') == -1){
462                                 ProcessFile (spec);
463                                 return;
464                         }
465
466                         string [] files = null;
467                         try {
468                                 files = Directory.GetFiles (path, pattern);
469                         } catch (System.IO.DirectoryNotFoundException) {
470                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
471                                 return;
472                         } catch (System.IO.IOException){
473                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
474                                 return;
475                         }
476                         foreach (string f in files) {
477                                 ProcessFile (f);
478                         }
479
480                         if (!recurse)
481                                 return;
482                         
483                         string [] dirs = null;
484
485                         try {
486                                 dirs = Directory.GetDirectories (path);
487                         } catch {
488                         }
489                         
490                         foreach (string d in dirs) {
491                                         
492                                 // Don't include path in this string, as each
493                                 // directory entry already does
494                                 CompileFiles (d + "/" + pattern, true);
495                         }
496                 }
497
498                 static void DefineDefaultConfig ()
499                 {
500                         //
501                         // For now the "default config" is harcoded into the compiler
502                         // we can move this outside later
503                         //
504                         string [] default_config = {
505                                 "System",
506                                 "System.Xml",
507 #if false
508                                 //
509                                 // Is it worth pre-loading all this stuff?
510                                 //
511                                 "Accessibility",
512                                 "System.Configuration.Install",
513                                 "System.Data",
514                                 "System.Design",
515                                 "System.DirectoryServices",
516                                 "System.Drawing.Design",
517                                 "System.Drawing",
518                                 "System.EnterpriseServices",
519                                 "System.Management",
520                                 "System.Messaging",
521                                 "System.Runtime.Remoting",
522                                 "System.Runtime.Serialization.Formatters.Soap",
523                                 "System.Security",
524                                 "System.ServiceProcess",
525                                 "System.Web",
526                                 "System.Web.RegularExpressions",
527                                 "System.Web.Services",
528                                 "System.Windows.Forms"
529 #endif
530                         };
531                         
532                         int p = 0;
533                         foreach (string def in default_config)
534                                 soft_references.Insert (p++, def);
535                 }
536
537                 static void SetOutputFile (string name)
538                 {
539                         output_file = name;
540                 }
541
542                 static void SetWarningLevel (string s)
543                 {
544                         int level = 0;
545
546                         try {
547                                 level = Int32.Parse (s);
548                         } catch {
549                                 Report.Error (
550                                         1900,
551                                         "--wlevel requires a value from 0 to 4");
552                                 Environment.Exit (1);
553                         }
554                         if (level < 0 || level > 4){
555                                 Report.Error (1900, "Warning level must be 0 to 4");
556                                 Environment.Exit (1);
557                         }
558                         RootContext.WarningLevel = level;
559                         TestWarningConflict ();
560                 }
561
562                 static void TestWarningConflict ()
563                 {
564                         if (RootContext.WarningLevel == 0 && Report.WarningsAreErrors) {
565                                 Report.Error (1901, "Conflicting options specified: Warning level 0; Treat warnings as errors");
566                                 Environment.Exit (1);
567                         }
568                 }
569
570                 static void SetupV2 ()
571                 {
572                         RootContext.V2 = true;
573                         defines.Add ("__V2__");
574                 }
575                 
576                 static void Version ()
577                 {
578                         string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
579                         Console.WriteLine ("Mono C# compiler version {0}", version);
580                         Environment.Exit (0);
581                 }
582                 
583                 //
584                 // Currently handles the Unix-like command line options, but will be
585                 // deprecated in favor of the CSCParseOption, which will also handle the
586                 // options that start with a dash in the future.
587                 //
588                 static bool UnixParseOption (string arg, ref string [] args, ref int i)
589                 {
590                         switch (arg){
591                         case "-vv":
592                                 parser_verbose = true;
593                                 return true;
594                                 
595                         case "-v":
596                                 yacc_verbose = true;
597                                 return true;
598
599                         case "--version":
600                                 Version ();
601                                 return true;
602                                 
603                         case "--parse":
604                                 parse_only = true;
605                                 return true;
606                                 
607                         case "--main": case "-m":
608                                 if ((i + 1) >= args.Length){
609                                         Usage ();
610                                         Environment.Exit (1);
611                                 }
612                                 RootContext.MainClass = args [++i];
613                                 return true;
614                                 
615                         case "--unsafe":
616                                 RootContext.Unsafe = true;
617                                 return true;
618                                 
619                         case "/?": case "/h": case "/help":
620                         case "--help":
621                                 Usage ();
622                                 Environment.Exit (0);
623                                 return true;
624                                 
625                         case "--define":
626                                 if ((i + 1) >= args.Length){
627                                         Usage ();
628                                         Environment.Exit (1);
629                                 }
630                                 defines.Add (args [++i]);
631                                 return true;
632
633                         case "--show-counters":
634                                 show_counters = true;
635                                 return true;
636                                 
637                         case "--expect-error": {
638                                 int code = 0;
639                                 
640                                 try {
641                                         code = Int32.Parse (
642                                                 args [++i], NumberStyles.AllowLeadingSign);
643                                         Report.ExpectedError = code;
644                                 } catch {
645                                         Report.Error (-14, "Invalid number specified");
646                                 } 
647                                 return true;
648                         }
649                                 
650                         case "--tokenize": 
651                                 tokenize = true;
652                                 return true;
653                                 
654                         case "-o": 
655                         case "--output":
656                                 if ((i + 1) >= args.Length){
657                                         Usage ();
658                                         Environment.Exit (1);
659                                 }
660                                 SetOutputFile (args [++i]);
661                                 return true;
662                                 
663                         case "--checked":
664                                 RootContext.Checked = true;
665                                 return true;
666                                 
667                         case "--stacktrace":
668                                 Report.Stacktrace = true;
669                                 return true;
670                                 
671                         case "--linkresource":
672                         case "--linkres":
673                                 if ((i + 1) >= args.Length){
674                                         Usage ();
675                                         Report.Error (5, "Missing argument to --linkres"); 
676                                         Environment.Exit (1);
677                                 }
678                                 if (resources == null)
679                                         resources = new ArrayList ();
680                                 
681                                 resources.Add (args [++i]);
682                                 return true;
683                                 
684                         case "--resource":
685                         case "--res":
686                                 if ((i + 1) >= args.Length){
687                                         Usage ();
688                                         Report.Error (5, "Missing argument to --resource"); 
689                                         Environment.Exit (1);
690                                 }
691                                 if (embedded_resources == null)
692                                         embedded_resources = new ArrayList ();
693                                 
694                                 embedded_resources.Add (args [++i]);
695                                 return true;
696                                 
697                         case "--target":
698                                 if ((i + 1) >= args.Length){
699                                         Environment.Exit (1);
700                                         return true;
701                                 }
702                                 
703                                 string type = args [++i];
704                                 switch (type){
705                                 case "library":
706                                         target = Target.Library;
707                                         target_ext = ".dll";
708                                         break;
709                                         
710                                 case "exe":
711                                         target = Target.Exe;
712                                         break;
713                                         
714                                 case "winexe":
715                                         target = Target.WinExe;
716                                         break;
717                                         
718                                 case "module":
719                                         target = Target.Module;
720                                         target_ext = ".dll";
721                                         break;
722                                 default:
723                                         TargetUsage ();
724                                         Environment.Exit (1);
725                                         break;
726                                 }
727                                 return true;
728                                 
729                         case "-r":
730                                 if ((i + 1) >= args.Length){
731                                         Usage ();
732                                         Environment.Exit (1);
733                                 }
734                                 
735                                 references.Add (args [++i]);
736                                 return true;
737                                 
738                         case "-L":
739                                 if ((i + 1) >= args.Length){
740                                         Usage ();       
741                                         Environment.Exit (1);
742                                 }
743                                 link_paths.Add (args [++i]);
744                                 return true;
745                                 
746                         case "--nostdlib":
747                                 RootContext.StdLib = false;
748                                 return true;
749                                 
750                         case "--fatal":
751                                 Report.Fatal = true;
752                                 return true;
753                                 
754                         case "--werror":
755                                 Report.WarningsAreErrors = true;
756                                 TestWarningConflict();
757                                 return true;
758                                 
759                         case "--nowarn":
760                                 if ((i + 1) >= args.Length){
761                                         Usage ();
762                                         Environment.Exit (1);
763                                 }
764                                 int warn = 0;
765                                 
766                                 try {
767                                         warn = Int32.Parse (args [++i]);
768                                 } catch {
769                                         Usage ();
770                                         Environment.Exit (1);
771                                 }
772                                 Report.SetIgnoreWarning (warn);
773                                 return true;
774                                 
775                         case "--wlevel":
776                                 if ((i + 1) >= args.Length){
777                                         Report.Error (
778                                                 1900,
779                                                 "--wlevel requires a value from 0 to 4");
780                                         Environment.Exit (1);
781                                 }
782
783                                 SetWarningLevel (args [++i]);
784                                 return true;
785
786                         case "--mcs-debug":
787                                 if ((i + 1) >= args.Length){
788                                         Report.Error (5, "--mcs-debug requires an argument");
789                                         Environment.Exit (1);
790                                 }
791
792                                 try {
793                                         Report.DebugFlags = Int32.Parse (args [++i]);
794                                 } catch {
795                                         Report.Error (5, "Invalid argument to --mcs-debug");
796                                         Environment.Exit (1);
797                                 }
798                                 return true;
799                                 
800                         case "--about":
801                                 About ();
802                                 return true;
803                                 
804                         case "--recurse":
805                                 if ((i + 1) >= args.Length){
806                                         Report.Error (5, "--recurse requires an argument");
807                                         Environment.Exit (1);
808                                 }
809                                 CompileFiles (args [++i], true); 
810                                 return true;
811                                 
812                         case "--timestamp":
813                                 timestamps = true;
814                                 last_time = first_time = DateTime.Now;
815                                 return true;
816
817                         case "--pause":
818                                 pause = true;
819                                 return true;
820                                 
821                         case "--debug": case "-g":
822                                 want_debugging_support = true;
823                                 return true;
824                                 
825                         case "--noconfig":
826                                 load_default_config = false;
827                                 return true;
828                         }
829
830                         return false;
831                 }
832
833                 //
834                 // Currently it is very basic option parsing, but eventually, this will
835                 // be the complete option parser
836                 //
837                 static bool CSCParseOption (string option, ref string [] args, ref int i)
838                 {
839                         int idx = option.IndexOf (':');
840                         string arg, value;
841
842                         if (idx == -1){
843                                 arg = option;
844                                 value = "";
845                         } else {
846                                 arg = option.Substring (0, idx);
847
848                                 value = option.Substring (idx + 1);
849                         }
850
851                         switch (arg){
852                         case "/nologo":
853                                 return true;
854
855                         case "/t":
856                         case "/target":
857                                 switch (value){
858                                 case "exe":
859                                         target = Target.Exe;
860                                         break;
861
862                                 case "winexe":
863                                         target = Target.WinExe;
864                                         break;
865
866                                 case "library":
867                                         target = Target.Library;
868                                         target_ext = ".dll";
869                                         break;
870
871                                 case "module":
872                                         target = Target.Module;
873                                         target_ext = ".netmodule";
874                                         break;
875
876                                 default:
877                                         TargetUsage ();
878                                         Environment.Exit (1);
879                                         break;
880                                 }
881                                 return true;
882
883                         case "/out":
884                                 if (value == ""){
885                                         Usage ();
886                                         Environment.Exit (1);
887                                 }
888                                 SetOutputFile (value);
889                                 return true;
890
891                         case "/optimize":
892                         case "/optimize+":
893                         case "/optimize-":
894                         case "/incremental":
895                         case "/incremental+":
896                         case "/incremental-":
897                                 // nothing.
898                                 return true;
899
900                         case "/d":
901                         case "/define": {
902                                 string [] defs;
903
904                                 if (value == ""){
905                                         Usage ();
906                                         Environment.Exit (1);
907                                 }
908
909                                 defs = value.Split (new Char [] {';', ','});
910                                 foreach (string d in defs){
911                                         defines.Add (d);
912                                 }
913                                 return true;
914                         }
915
916                         case "/linkres":
917                         case "/linkresource":
918                                 if (value == ""){
919                                         Report.Error (5, arg + " requires an argument");
920                                         Environment.Exit (1);
921                                 }
922                                 if (resources == null)
923                                         resources = new ArrayList ();
924                                 
925                                 resources.Add (value);
926                                 return true;
927                                 
928                         case "/res":
929                         case "/resource":
930                                 if (value == ""){
931                                         Report.Error (5, arg + " requires an argument");
932                                         Environment.Exit (1);
933                                 }
934                                 if (embedded_resources == null)
935                                         embedded_resources = new ArrayList ();
936                                 
937                                 embedded_resources.Add (value);
938                                 return true;
939                                 
940                         case "/recurse":
941                                 if (value == ""){
942                                         Report.Error (5, "/recurse requires an argument");
943                                         Environment.Exit (1);
944                                 }
945                                 CompileFiles (value, true); 
946                                 return true;
947
948                         case "/r":
949                         case "/reference": {
950                                 if (value == ""){
951                                         Report.Error (5, arg + " requires an argument");
952                                         Environment.Exit (1);
953                                 }
954
955                                 string [] refs = value.Split (new char [] { ';', ',' });
956                                 foreach (string r in refs){
957                                         references.Add (r);
958                                 }
959                                 return true;
960                         }
961                         case "/doc": {
962                                 if (value == ""){
963                                         Report.Error (5, arg + " requires an argument");
964                                         Environment.Exit (1);
965                                 }
966                                 // TODO handle the /doc argument to generate xml doc
967                                 return true;
968                         }
969                         case "/lib": {
970                                 string [] libdirs;
971                                 
972                                 if (value == ""){
973                                         Report.Error (5, "/lib requires an argument");
974                                         Environment.Exit (1);
975                                 }
976
977                                 libdirs = value.Split (new Char [] { ',' });
978                                 foreach (string dir in libdirs)
979                                         link_paths.Add (dir);
980                                 return true;
981                         }
982                                 
983                         case "/debug":
984                         case "/debug+":
985                                 want_debugging_support = true;
986                                 return true;
987
988                         case "/checked":
989                         case "/checked+":
990                                 RootContext.Checked = true;
991                                 return true;
992
993                         case "/checked-":
994                                 RootContext.Checked = false;
995                                 return true;
996
997                         case "/unsafe":
998                         case "/unsafe+":
999                                 RootContext.Unsafe = true;
1000                                 return true;
1001
1002                         case "/unsafe-":
1003                                 RootContext.Unsafe = false;
1004                                 return true;
1005
1006                         case "/warnaserror":
1007                         case "/warnaserror+":
1008                                 Report.WarningsAreErrors = true;
1009                                 TestWarningConflict();
1010                                 return true;
1011
1012                         case "/warnaserror-":
1013                                 Report.WarningsAreErrors = false;
1014                                 return true;
1015
1016                         case "/warn":
1017                                 SetWarningLevel (value);
1018                                 return true;
1019
1020                         case "/nowarn": {
1021                                 string [] warns;
1022
1023                                 if (value == ""){
1024                                         Report.Error (5, "/nowarn requires an argument");
1025                                         Environment.Exit (1);
1026                                 }
1027                                 
1028                                 warns = value.Split (new Char [] {','});
1029                                 foreach (string wc in warns){
1030                                         try {
1031                                                 int warn = Int32.Parse (wc);
1032                                                 if (warn < 1) {
1033                                                         throw new ArgumentOutOfRangeException("warn");
1034                                                 }
1035                                                 Report.SetIgnoreWarning (warn);
1036                                         } catch {
1037                                                 Report.Error (1904, String.Format("'{0}' is not a valid warning number", wc));
1038                                                 Environment.Exit (1);
1039                                         }
1040                                 }
1041                                 return true;
1042                         }
1043
1044                         case "/noconfig-":
1045                                 load_default_config = true;
1046                                 return true;
1047                                 
1048                         case "/noconfig":
1049                         case "/noconfig+":
1050                                 load_default_config = false;
1051                                 return true;
1052
1053                         case "/help":
1054                         case "/?":
1055                                 Usage ();
1056                                 Environment.Exit (0);
1057                                 return true;
1058
1059                         case "/main":
1060                         case "/m":
1061                                 if (value == ""){
1062                                         Report.Error (5, arg + " requires an argument");                                        
1063                                         Environment.Exit (1);
1064                                 }
1065                                 RootContext.MainClass = value;
1066                                 return true;
1067
1068                         case "/nostdlib":
1069                         case "/nostdlib+":
1070                                 RootContext.StdLib = false;
1071                                 return true;
1072
1073                         case "/nostdlib-":
1074                                 RootContext.StdLib = true;
1075                                 return true;
1076
1077                         case "/fullpaths":
1078                                 return true;
1079
1080                         case "/win32icon":
1081                                 Report.Error (5, "/win32icon is currently not supported");
1082                                 return true;
1083                                 
1084                         case "/v2":
1085                         case "/2":
1086                                 SetupV2 ();
1087                                 return true;
1088                                 
1089                         case "/codepage":
1090                                 int cp = -1;
1091
1092                                 if (value == "utf8"){
1093                                         encoding = new UTF8Encoding();
1094                                         using_default_encoder = false;
1095                                         return true;
1096                                 }
1097                                 if (value == "reset"){
1098                                         //
1099                                         // 28591 is the code page for ISO-8859-1 encoding.
1100                                         //
1101                                         cp = 28591;
1102                                         using_default_encoder = true;
1103                                 }
1104                                 
1105                                 try {
1106                                         cp = Int32.Parse (value);
1107                                         encoding = Encoding.GetEncoding (cp);
1108                                         using_default_encoder = false;
1109                                 } catch {
1110                                         Report.Error (2016, String.Format("Code page '{0}' is invalid or not installed", cp));
1111                                         Environment.Exit (1);
1112                                 }
1113                                 return true;
1114                         }
1115                         //Report.Error (2007, String.Format ("Unrecognized command-line option: '{0}'", option));
1116                         //Environment.Exit (1);
1117                         return false;
1118                 }
1119                 
1120                 /// <summary>
1121                 ///    Parses the arguments, and drives the compilation
1122                 ///    process.
1123                 /// </summary>
1124                 ///
1125                 /// <remarks>
1126                 ///    TODO: Mostly structured to debug the compiler
1127                 ///    now, needs to be turned into a real driver soon.
1128                 /// </remarks>
1129                 // [MonoTODO("Change error code for unknown argument to something reasonable")]
1130                 internal static bool MainDriver (string [] args)
1131                 {
1132                         int i;
1133                         bool parsing_options = true;
1134
1135                         try {
1136                                 encoding = Encoding.GetEncoding (28591);
1137                         } catch {
1138                                 Console.WriteLine ("Error: could not load encoding 28591, trying 1252");
1139                                 encoding = Encoding.GetEncoding (1252);
1140                         }
1141                         
1142                         references = new ArrayList ();
1143                         soft_references = new ArrayList ();
1144                         link_paths = new ArrayList ();
1145
1146                         SetupDefaultDefines ();
1147                         
1148                         //
1149                         // Setup defaults
1150                         //
1151                         // This is not required because Assembly.Load knows about this
1152                         // path.
1153                         //
1154
1155                         int argc = args.Length;
1156                         for (i = 0; i < argc; i++){
1157                                 string arg = args [i];
1158
1159                                 if (arg.StartsWith ("@")){
1160                                         string [] new_args, extra_args;
1161                                         string response_file = arg.Substring (1);
1162
1163                                         if (response_file_list == null)
1164                                                 response_file_list = new Hashtable ();
1165                                         
1166                                         if (response_file_list.Contains (response_file)){
1167                                                 Report.Error (
1168                                                         1515, "Response file `" + response_file +
1169                                                         "' specified multiple times");
1170                                                 Environment.Exit (1);
1171                                         }
1172                                         
1173                                         response_file_list.Add (response_file, response_file);
1174                                                     
1175                                         extra_args = LoadArgs (response_file);
1176                                         if (extra_args == null){
1177                                                 Report.Error (2011, "Unable to open response file: " +
1178                                                               response_file);
1179                                                 return false;
1180                                         }
1181
1182                                         new_args = new string [extra_args.Length + argc];
1183                                         args.CopyTo (new_args, 0);
1184                                         extra_args.CopyTo (new_args, argc);
1185                                         args = new_args;
1186                                         argc = new_args.Length;
1187                                         continue;
1188                                 }
1189
1190                                 if (parsing_options){
1191                                         if (arg == "--"){
1192                                                 parsing_options = false;
1193                                                 continue;
1194                                         }
1195                                         
1196                                         if (arg.StartsWith ("-")){
1197                                                 if (UnixParseOption (arg, ref args, ref i))
1198                                                         continue;
1199
1200                                                 // Try a -CSCOPTION
1201                                                 string csc_opt = "/" + arg.Substring (1);
1202                                                 if (CSCParseOption (csc_opt, ref args, ref i))
1203                                                         continue;
1204                                         } else {
1205                                                 if (arg.StartsWith ("/")){
1206                                                         if (CSCParseOption (arg, ref args, ref i))
1207                                                                 continue;
1208                                                 }
1209                                         }
1210                                 }
1211
1212                                 CompileFiles (arg, false); 
1213                         }
1214
1215                         ProcessFiles ();
1216
1217                         if (tokenize)
1218                                 return true;
1219                         
1220                         if (first_source == null){
1221                                 Report.Error (2008, "No files to compile were specified");
1222                                 return false;
1223                         }
1224
1225                         if (Report.Errors > 0)
1226                                 return false;
1227                         
1228                         if (parse_only)
1229                                 return true;
1230                         
1231                         //
1232                         // Load Core Library for default compilation
1233                         //
1234                         if (RootContext.StdLib)
1235                                 references.Insert (0, "mscorlib");
1236
1237                         if (load_default_config)
1238                                 DefineDefaultConfig ();
1239
1240                         if (Report.Errors > 0){
1241                                 return false;
1242                         }
1243
1244                         //
1245                         // Load assemblies required
1246                         //
1247                         if (timestamps)
1248                                 ShowTime ("Loading references");
1249                         link_paths.Add (GetSystemDir ());
1250                         LoadReferences ();
1251                         
1252                         if (timestamps)
1253                                 ShowTime ("   References loaded");
1254                         
1255                         if (Report.Errors > 0){
1256                                 return false;
1257                         }
1258
1259                         //
1260                         // Quick hack
1261                         //
1262                         if (output_file == null){
1263                                 int pos = first_source.LastIndexOf ('.');
1264
1265                                 if (pos > 0)
1266                                         output_file = first_source.Substring (0, pos) + target_ext;
1267                                 else
1268                                         output_file = first_source + target_ext;
1269                         }
1270
1271                         CodeGen.Init (output_file, output_file, want_debugging_support);
1272
1273                         TypeManager.AddModule (CodeGen.ModuleBuilder);
1274
1275                         DateTime start = DateTime.Now;
1276                         TypeManager.ComputeNamespaces ();
1277                         DateTime end = DateTime.Now;
1278                         
1279                         //
1280                         // Before emitting, we need to get the core
1281                         // types emitted from the user defined types
1282                         // or from the system ones.
1283                         //
1284                         if (timestamps)
1285                                 ShowTime ("Initializing Core Types");
1286                         if (!RootContext.StdLib){
1287                                 RootContext.ResolveCore ();
1288                                 if (Report.Errors > 0)
1289                                         return false;
1290                         }
1291                         
1292                         TypeManager.InitCoreTypes ();
1293                         if (timestamps)
1294                                 ShowTime ("   Core Types done");
1295
1296                         //
1297                         // The second pass of the compiler
1298                         //
1299                         if (timestamps)
1300                                 ShowTime ("Resolving tree");
1301                         RootContext.ResolveTree ();
1302                         if (Report.Errors > 0)
1303                                 return false;
1304                         if (timestamps)
1305                                 ShowTime ("Populate tree");
1306                         if (!RootContext.StdLib)
1307                                 RootContext.BootCorlib_PopulateCoreTypes ();
1308                         RootContext.PopulateTypes ();
1309                         RootContext.DefineTypes ();
1310                         
1311                         TypeManager.InitCodeHelpers ();
1312
1313                         //
1314                         // Verify using aliases now
1315                         //
1316                         Namespace.VerifyUsing ();
1317                         
1318                         if (Report.Errors > 0){
1319                                 return false;
1320                         }
1321                         
1322                         //
1323                         // The code generator
1324                         //
1325                         if (timestamps)
1326                                 ShowTime ("Emitting code");
1327                         ShowTotalTime ("Total so far");
1328                         RootContext.EmitCode ();
1329                         if (timestamps)
1330                                 ShowTime ("   done");
1331
1332                         if (Report.Errors > 0){
1333                                 return false;
1334                         }
1335
1336                         if (timestamps)
1337                                 ShowTime ("Closing types");
1338
1339                         RootContext.CloseTypes ();
1340
1341                         PEFileKinds k = PEFileKinds.ConsoleApplication;
1342                                 
1343                         if (target == Target.Library || target == Target.Module){
1344                                 k = PEFileKinds.Dll;
1345
1346                                 if (RootContext.MainClass != null)
1347                                         Report.Error (2017, "Can not specify -main: when building module or library");
1348                         } else if (target == Target.Exe)
1349                                 k = PEFileKinds.ConsoleApplication;
1350                         else if (target == Target.WinExe)
1351                                 k = PEFileKinds.WindowApplication;
1352
1353                         if (target == Target.Exe || target == Target.WinExe){
1354                                 MethodInfo ep = RootContext.EntryPoint;
1355
1356                                 if (ep == null){
1357                                         if (Report.Errors == 0)
1358                                                 Report.Error (5001, "Program " + output_file +
1359                                                               " does not have an entry point defined");
1360                                         return false;
1361                                 }
1362                                 
1363                                 CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
1364                         }
1365
1366                         //
1367                         // Add the resources
1368                         //
1369                         if (resources != null){
1370                                 foreach (string spec in resources){
1371                                         string file, res;
1372                                         int cp;
1373                                         
1374                                         cp = spec.IndexOf (',');
1375                                         if (cp != -1){
1376                                                 file = spec.Substring (0, cp);
1377                                                 res = spec.Substring (cp + 1);
1378                                         } else
1379                                                 file = res = spec;
1380
1381                                         CodeGen.AssemblyBuilder.AddResourceFile (res, file);
1382                                 }
1383                         }
1384                         
1385                         if (embedded_resources != null){
1386                                 object[] margs = new object [2];
1387                                 Type[] argst = new Type [2];
1388                                 argst [0] = argst [1] = typeof (string);
1389
1390                                 MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic, null, CallingConventions.Any, argst, null);
1391                                 if (embed_res == null) {
1392                                         Report.Warning (0, new Location (-1), "Cannot embed resources on this runtime: try the Mono runtime instead.");
1393                                 } else {
1394                                         foreach (string spec in embedded_resources) {
1395                                                 int cp;
1396
1397                                                 cp = spec.IndexOf (',');
1398                                                 if (cp != -1){
1399                                                         margs [0] = spec.Substring (cp + 1);
1400                                                         margs [1] = spec.Substring (0, cp);
1401                                                 } else
1402                                                         margs [0] = margs [1] = spec;
1403
1404                                                 if (File.Exists ((string) margs [1]))
1405                                                         embed_res.Invoke (CodeGen.AssemblyBuilder, margs);
1406                                                 else {
1407                                                         Report.Error (1566, "Can not find the resource " + margs [1]);
1408                                                 }
1409                                         }
1410                                 }
1411                         }
1412
1413                         if (Report.Errors > 0)
1414                                 return false;
1415                         
1416                         CodeGen.Save (output_file);
1417                         if (timestamps) {
1418                                 ShowTime ("Saved output");
1419                                 ShowTotalTime ("Total");
1420                         }
1421
1422                         Timer.ShowTimers ();
1423                         
1424                         if (Report.ExpectedError != 0){
1425                                 Console.WriteLine("Failed to report expected error " + Report.ExpectedError);
1426                                 Environment.Exit (1);
1427                                 return false;
1428                         }
1429
1430 #if DEBUGME
1431                         Console.WriteLine ("Size of strings held: " + DeclSpace.length);
1432                         Console.WriteLine ("Size of strings short: " + DeclSpace.small);
1433 #endif
1434                         return (Report.Errors == 0);
1435                 }
1436
1437         }
1438
1439         //
1440         // This is the only public entry point
1441         //
1442         public class CompilerCallableEntryPoint : MarshalByRefObject {
1443                 static bool used = false;
1444                 
1445                 public bool InvokeCompiler (string [] args)
1446                 {
1447                         if (used)
1448                                 Reset ();
1449                         bool ok = Driver.MainDriver (args);
1450                         return ok && Report.Errors == 0;
1451                 }
1452
1453                 public void Reset ()
1454                 {
1455                 }
1456         }
1457 }