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