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