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