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