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