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