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