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