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