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