2002-03-27 Miguel de Icaza <miguel@ximian.com>
[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 Ximian, Inc (http://www.ximian.com)
9 //
10
11 namespace Mono.CSharp
12 {
13         using System;
14         using System.Reflection;
15         using System.Reflection.Emit;
16         using System.Collections;
17         using System.IO;
18         using System.Globalization;
19         using Mono.Languages;
20
21         enum Target {
22                 Library, Exe, Module, WinExe
23         };
24         
25         /// <summary>
26         ///    The compiler driver.
27         /// </summary>
28         public class Driver
29         {
30                 
31                 //
32                 // Assemblies references to be linked.   Initialized with
33                 // mscorlib.dll here.
34                 static ArrayList references;
35
36                 //
37                 // If any of these fail, we ignore the problem.  This is so
38                 // that we can list all the assemblies in Windows and not fail
39                 // if they are missing on Linux.
40                 //
41                 static ArrayList soft_references;
42
43                 // Lookup paths
44                 static ArrayList link_paths;
45
46                 // Whether we want Yacc to output its progress
47                 static bool yacc_verbose = false;
48
49                 // Whether we want to only run the tokenizer
50                 static bool tokenize = false;
51                 
52                 static int error_count = 0;
53
54                 static string first_source;
55
56                 static Target target = Target.Exe;
57                 static string target_ext = ".exe";
58
59                 static bool want_debugging_support = false;
60
61                 static bool parse_only = false;
62                 static bool timestamps = false;
63
64                 //
65                 // Whether to load the initial config file (what CSC.RSP has by default)
66                 // 
67                 static bool load_default_config = true;
68
69                 static Hashtable response_file_list;
70                 static Hashtable source_files = new Hashtable ();
71
72                 //
73                 // A list of resource files
74                 //
75                 static ArrayList resources;
76                 
77                 //
78                 // An array of the defines from the command line
79                 //
80                 static ArrayList defines;
81
82                 //
83                 // Last time we took the time
84                 //
85                 static DateTime last_time;
86                 static void ShowTime (string msg)
87                 {
88                         DateTime now = DateTime.Now;
89                         TimeSpan span = now - last_time;
90                         last_time = now;
91                         
92                         Console.WriteLine (
93                                 "[{0:00}:{1:000}] {2}",
94                                 span.Seconds, span.Milliseconds, msg);
95                 }
96                 
97                 static int tokenize_file (string input_file)
98                 {
99                         Stream input;
100
101                         try {
102                                 input = File.OpenRead (input_file);
103
104                         } catch {
105                                 Report.Error (2001, "Source file '" + input_file + "' could not be opened");
106                                 return 1;
107                         }
108
109                         using (input){
110                                 Tokenizer lexer = new Tokenizer (input, input_file, defines);
111                                 int token, tokens = 0, errors = 0;
112
113                                 while ((token = lexer.token ()) != Token.EOF){
114                                         Location l = lexer.Location;
115                                         tokens++;
116                                         if (token == Token.ERROR)
117                                                 errors++;
118                                 }
119                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
120                         }
121                         
122                         return 0;
123                 }
124                 
125                 static int parse (string input_file)
126                 {
127                         CSharpParser parser;
128                         Stream input;
129                         int errors;
130
131                         try {
132                                 input = File.OpenRead (input_file);
133                         } catch {
134                                 Report.Error (2001, "Source file '" + input_file + "' could not be opened");
135                                 return 1;
136                         }
137
138                         parser = new CSharpParser (input_file, input, defines);
139                         parser.yacc_verbose = yacc_verbose;
140                         try {
141                                 errors = parser.parse ();
142                         } catch (Exception ex) {
143                                 Console.WriteLine (ex);
144                                 Console.WriteLine ("Compilation aborted");
145                                 return 1;
146                         } finally {
147                                 input.Close ();
148                         }
149                         
150                         return errors;
151                 }
152                 
153                 static void Usage (bool is_error)
154                 {
155                         Console.WriteLine (
156                                 "Mono C# compiler, (C) 2001 Ximian, Inc.\n" +
157                                 "mcs [options] source-files\n" +
158                                 "   --about         About the Mono C# compiler\n" +
159                                 "   --checked       Set default context to checked\n" +
160                                 "   --define SYM    Defines the symbol SYM\n" +
161                                 "   --debug         Generate debugging information\n" + 
162                                 "   -g              Generate debugging information\n" +
163                                 "   --fatal         Makes errors fatal\n" +
164                                 "   -L PATH         Adds PATH to the assembly link path\n" +
165                                 "   --noconfig      Disables implicit references to assemblies\n" +
166                                 "   --nostdlib      Does not load core libraries\n" +
167                                 "   --nowarn XXX    Ignores warning number XXX\n" +
168                                 "   -o FNAME        Specifies output file\n" +
169                                 "   --optimize      Optimizes\n" +
170                                 "   -g, --debug     Write symbolic debugging information to FILE-debug.s\n" +
171                                 "   --parse         Only parses the source file\n" +
172                                 "   --probe X       Probes for the source to generate code X on line L\n" +
173                                 "   --recurse SPEC  Recursively compiles the files in SPEC ([dir]/file)\n" + 
174                                 "   --resource FILE Addds FILE as a resource\n" + 
175                                 "   --stacktrace    Shows stack trace at error location\n" +
176                                 "   --target KIND   Specifies the target (KIND is one of: exe, winexe, " +
177                                                     "library, module)\n" +
178                                 "   --timestamp     Displays time stamps of various compiler events\n" +
179                                 "   --unsafe        Allows unsafe code\n" +
180                                 "   --werror        Treat warnings as errors\n" +
181                                 "   --wlevel LEVEL  Sets warning level (the highest is 4, the default)\n" +
182                                 "   -r              References an assembly\n" +
183                                 "   -v              Verbose parsing (for debugging the parser)\n" +
184                                 "   @file           Read response file for more options");
185                         if (is_error)
186                                 error_count++;
187                 }
188
189                 static void About ()
190                 {
191                         Console.WriteLine (
192                                 "The Mono C# compiler is (C) 2001 Ximian, Inc.\n\n" +
193                                 "The compiler source code is released under the terms of the GNU GPL\n\n" +
194
195                                 "For more information on Mono, visit the project Web site\n" +
196                                 "   http://www.go-mono.com\n\n" +
197
198                                 "The compiler was written by Miguel de Icaza and Ravi Pratap");
199                 }
200                 
201                 static void error (string msg)
202                 {
203                         Console.WriteLine ("Error: " + msg);
204                 }
205
206                 static void notice (string msg)
207                 {
208                         Console.WriteLine (msg);
209                 }
210                 
211                 public static int Main (string[] args)
212                 {
213                         MainDriver (args);
214                         
215                         return (error_count + Report.Errors) != 0 ? 1 : 0;
216                 }
217
218                 static public int LoadAssembly (string assembly, bool soft)
219                 {
220                         Assembly a;
221                         string total_log = "";
222
223                         try {
224                                 a = Assembly.Load (assembly);
225                                 TypeManager.AddAssembly (a);
226                                 return 0;
227                         } catch (FileNotFoundException){
228                                 foreach (string dir in link_paths){
229                                         string full_path = dir + "/" + assembly + ".dll";
230
231                                         try {
232                                                 a = Assembly.LoadFrom (full_path);
233                                                 TypeManager.AddAssembly (a);
234                                                 return 0;
235                                         } catch (FileNotFoundException ff) {
236                                                 total_log += ff.FusionLog;
237                                                 continue;
238                                         }
239                                 }
240                                 if (soft)
241                                         return 0;
242                         } catch (BadImageFormatException f) {
243                                 error ("// Bad file format while loading assembly");
244                                 error ("Log: " + f.FusionLog);
245                                 return 1;
246                         } catch (FileLoadException f){
247                                 error ("// File Load Exception: ");
248                                 error ("Log: " + f.FusionLog);
249                                 return 1;
250                         } catch (ArgumentNullException){
251                                 error ("// Argument Null exception ");
252                                 return 1;
253                         }
254                         
255                         Report.Error (6, "Can not find assembly `" + assembly + "'" );
256                         Console.WriteLine ("Log: \n" + total_log);
257
258                         return 0;
259                 }
260
261                 /// <summary>
262                 ///   Loads all assemblies referenced on the command line
263                 /// </summary>
264                 static public int LoadReferences ()
265                 {
266                         int errors = 0;
267
268                         foreach (string r in references)
269                                 errors += LoadAssembly (r, false);
270
271                         foreach (string r in soft_references)
272                                 errors += LoadAssembly (r, true);
273                         
274                         return errors;
275                 }
276
277                 static void SetupDefaultDefines ()
278                 {
279                         defines = new ArrayList ();
280                         defines.Add ("__MonoCS__");
281                 }
282
283                 static string [] LoadArgs (string file)
284                 {
285                         StreamReader f;
286                         ArrayList args = new ArrayList ();
287                         string line;
288                         try {
289                                 f = new StreamReader (file);
290                         } catch {
291                                 return null;
292                         }
293
294                         while ((line = f.ReadLine ()) != null){
295                                 string [] line_args = line.Split (new char [] { ' ' });
296
297                                 foreach (string arg in line_args)
298                                         args.Add (arg);
299                         }
300
301                         string [] ret_value = new string [args.Count];
302                         args.CopyTo (ret_value, 0);
303
304                         return ret_value;
305                 }
306
307                 //
308                 // Returns the directory where the system assemblies are installed
309                 //
310                 static string GetSystemDir ()
311                 {
312                         Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
313
314                         foreach (Assembly a in assemblies){
315                                 string codebase = a.CodeBase;
316                                 if (codebase.EndsWith ("corlib.dll")){
317                                         return codebase.Substring (0, codebase.LastIndexOf ("/"));
318                                 }
319                         }
320
321                         Report.Error (-15, "Can not compute my system path");
322                         return "";
323                 }
324
325                 //
326                 // Given a path specification, splits the path from the file/pattern
327                 //
328                 static void SplitPathAndPattern (string spec, out string path, out string pattern)
329                 {
330                         int p = spec.LastIndexOf ("/");
331                         if (p != -1){
332                                 //
333                                 // Windows does not like /file.cs, switch that to:
334                                 // "\", "file.cs"
335                                 //
336                                 if (p == 0){
337                                         path = "\\";
338                                         pattern = spec.Substring (1);
339                                 } else {
340                                         path = spec.Substring (0, p);
341                                         pattern = spec.Substring (p + 1);
342                                 }
343                                 return;
344                         }
345
346                         p = spec.LastIndexOf ("\\");
347                         if (p != -1){
348                                 path = spec.Substring (0, p);
349                                 pattern = spec.Substring (p + 1);
350                                 return;
351                         }
352
353                         path = ".";
354                         pattern = spec;
355                 }
356
357                 static int ProcessFile (string f)
358                 {
359                         if (first_source == null)
360                                 first_source = f;
361
362                         if (source_files.Contains (f)){
363                                 Report.Error (
364                                         1516,
365                                         "Source file `" + f + "' specified multiple times");
366                                 Environment.Exit (1);
367                         } else
368                                 source_files.Add (f, f);
369                                         
370                         if (tokenize)
371                                 tokenize_file (f);
372                         else
373                                 return parse (f);
374                         return 0;
375                 }
376
377                 static int CompileFiles (string spec, bool recurse)
378                 {
379                         string path, pattern;
380                         int errors = 0;
381
382                         SplitPathAndPattern (spec, out path, out pattern);
383                         string [] files = null;
384                         try {
385                                 files = Directory.GetFiles (path, pattern);
386                         } catch (System.IO.DirectoryNotFoundException) {
387                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
388                                 return 1;
389                         } catch (System.IO.IOException){
390                                 Report.Error (2001, "Source file `" + spec + "' could not be found");
391                                 return 1;
392                         }
393                                 
394                         foreach (string f in files)
395                                 errors += ProcessFile (f);
396
397                         if (!recurse)
398                                 return errors;
399                         
400                         string [] dirs = null;
401
402                         try {
403                                 dirs = Directory.GetDirectories (path);
404                         } catch {
405                         }
406                         
407                         foreach (string d in dirs)
408                                 errors += CompileFiles (path + "\\" + d + "\\" + pattern, true);
409
410                         return errors;
411                 }
412
413                 static void DefineDefaultConfig ()
414                 {
415                         //
416                         // For now the "default config" is harcoded into the compiler
417                         // we can move this outside later
418                         //
419                         string [] default_config = {
420                                 "System",
421                                 "System.Xml",
422 #if false
423                                 //
424                                 // Is it worth pre-loading all this stuff?
425                                 //
426                                 "Accessibility",
427                                 "System.Configuration.Install",
428                                 "System.Data",
429                                 "System.Design",
430                                 "System.DirectoryServices",
431                                 "System.Drawing.Design",
432                                 "System.Drawing",
433                                 "System.EnterpriseServices",
434                                 "System.Management",
435                                 "System.Messaging",
436                                 "System.Runtime.Remoting",
437                                 "System.Runtime.Serialization.Formatters.Soap",
438                                 "System.Security",
439                                 "System.ServiceProcess",
440                                 "System.Web",
441                                 "System.Web.RegularExpressions",
442                                 "System.Web.Services",
443                                 "System.Windows.Forms"
444 #endif
445                         };
446                         
447                         int p = 0;
448                         foreach (string def in default_config)
449                                 soft_references.Insert (p++, def);
450                 }
451                 
452                 /// <summary>
453                 ///    Parses the arguments, and drives the compilation
454                 ///    process.
455                 /// </summary>
456                 ///
457                 /// <remarks>
458                 ///    TODO: Mostly structured to debug the compiler
459                 ///    now, needs to be turned into a real driver soon.
460                 /// </remarks>
461                 static void MainDriver (string [] args)
462                 {
463                         int errors = 0, i;
464                         string output_file = null;
465                         bool parsing_options = true;
466                         
467                         references = new ArrayList ();
468                         soft_references = new ArrayList ();
469                         link_paths = new ArrayList ();
470
471                         SetupDefaultDefines ();
472                         
473                         //
474                         // Setup defaults
475                         //
476                         // This is not required because Assembly.Load knows about this
477                         // path.
478                         //
479                         link_paths.Add (GetSystemDir ());
480
481                         int argc = args.Length;
482                         for (i = 0; i < argc; i++){
483                                 string arg = args [i];
484
485                                 if (arg.StartsWith ("@")){
486                                         string [] new_args, extra_args;
487                                         string response_file = arg.Substring (1);
488
489                                         if (response_file_list == null)
490                                                 response_file_list = new Hashtable ();
491                                         
492                                         if (response_file_list.Contains (response_file)){
493                                                 Report.Error (
494                                                         1515, "Response file `" + response_file +
495                                                         "' specified multiple times");
496                                                 Environment.Exit (1);
497                                         }
498                                         
499                                         response_file_list.Add (response_file, response_file);
500                                                     
501                                         extra_args = LoadArgs (response_file);
502                                         if (extra_args == null){
503                                                 Report.Error (2011, "Unable to open response file: " +
504                                                               response_file);
505                                                 return;
506                                         }
507
508                                         new_args = new string [extra_args.Length + argc];
509                                         args.CopyTo (new_args, 0);
510                                         extra_args.CopyTo (new_args, argc);
511                                         args = new_args;
512                                         argc = new_args.Length;
513                                         continue;
514                                 }
515
516                                 //
517                                 // Prepare to recurse
518                                 //
519                                 
520                                 if (parsing_options && (arg.StartsWith ("-"))){
521                                         switch (arg){
522                                         case "-v":
523                                                 yacc_verbose = true;
524                                                 continue;
525
526                                         case "--":
527                                                 parsing_options = false;
528                                                 continue;
529
530                                         case "--parse":
531                                                 parse_only = true;
532                                                 continue;
533
534                                         case "--main": case "-m":
535                                                 if ((i + 1) >= argc){
536                                                         Usage (true);
537                                                         return;
538                                                 }
539                                                 RootContext.MainClass = args [++i];
540                                                 continue;
541
542                                         case "--unsafe":
543                                                 RootContext.Unsafe = true;
544                                                 continue;
545                                                 
546                                         case "--optimize":
547                                                 RootContext.Optimize = true;
548                                                 continue;
549
550                                         case "/?": case "/h": case "/help":
551                                         case "--help":
552                                                 Usage (false);
553                                                 return;
554
555                                         case "--define":
556                                                 if ((i + 1) >= argc){
557                                                         Usage (true);
558                                                         return;
559                                                 }
560                                                 defines.Add (args [++i]);
561                                                 continue;
562                                                 
563                                         case "--probe": {
564                                                 int code = 0;
565
566                                                 try {
567                                                         code = Int32.Parse (
568                                                                 args [++i], NumberStyles.AllowLeadingSign);
569                                                         Report.SetProbe (code);
570                                                 } catch {
571                                                         Report.Error (-14, "Invalid number specified");
572                                                 } 
573                                                 continue;
574                                         }
575
576                                         case "--tokenize": {
577                                                 tokenize = true;
578                                                 continue;
579                                         }
580                                         
581                                         case "-o": 
582                                         case "--output":
583                                                 if ((i + 1) >= argc){
584                                                         Usage (true);
585                                                         return;
586                                                 }
587                                                 output_file = args [++i];
588                                                 string bname = CodeGen.Basename (output_file);
589                                                 if (bname.IndexOf (".") == -1)
590                                                         output_file += ".exe";
591                                                 continue;
592
593                                         case "--checked":
594                                                 RootContext.Checked = true;
595                                                 continue;
596
597                                         case "--stacktrace":
598                                                 Report.Stacktrace = true;
599                                                 continue;
600
601                                         case "--resource":
602                                                 if ((i + 1) >= argc){
603                                                         Usage (true);
604                                                         Console.WriteLine("Missing argument to --resource"); 
605                                                         return;
606                                                 }
607                                                 if (resources == null)
608                                                         resources = new ArrayList ();
609                                                 
610                                                 resources.Add (args [++i]);
611                                                 continue;
612                                                         
613                                         case "--target":
614                                                 if ((i + 1) >= argc){
615                                                         Usage (true);
616                                                         return;
617                                                 }
618
619                                                 string type = args [++i];
620                                                 switch (type){
621                                                 case "library":
622                                                         target = Target.Library;
623                                                         target_ext = ".dll";
624                                                         break;
625                                                         
626                                                 case "exe":
627                                                         target = Target.Exe;
628                                                         break;
629                                                         
630                                                 case "winexe":
631                                                         target = Target.WinExe;
632                                                         break;
633                                                         
634                                                 case "module":
635                                                         target = Target.Module;
636                                                         target_ext = ".dll";
637                                                         break;
638                                                 default:
639                                                         Usage (true);
640                                                         return;
641                                                 }
642                                                 continue;
643
644                                         case "-r":
645                                                 if ((i + 1) >= argc){
646                                                         Usage (true);
647                                                         return;
648                                                 }
649                                                 
650                                                 references.Add (args [++i]);
651                                                 continue;
652                                                 
653                                         case "-L":
654                                                 if ((i + 1) >= argc){
655                                                         Usage (true);
656                                                         return;
657                                                 }
658                                                 link_paths.Add (args [++i]);
659                                                 continue;
660                                                 
661                                         case "--nostdlib":
662                                                 RootContext.StdLib = false;
663                                                 continue;
664                                                 
665                                         case "--fatal":
666                                                 Report.Fatal = true;
667                                                 continue;
668
669                                         case "--werror":
670                                                 Report.WarningsAreErrors = true;
671                                                 continue;
672
673                                         case "--nowarn":
674                                                 if ((i + 1) >= argc){
675                                                         Usage (true);
676                                                         return;
677                                                 }
678                                                 int warn;
679                                                 
680                                                 try {
681                                                         warn = Int32.Parse (args [++i]);
682                                                 } catch {
683                                                         Usage (true);
684                                                         return;
685                                                 }
686                                                 Report.SetIgnoreWarning (warn);
687                                                 continue;
688
689                                         case "--wlevel":
690                                                 if ((i + 1) >= argc){
691                                                         Report.Error (
692                                                                 1900,
693                                                                 "--wlevel requires an value from 0 to 4");
694                                                         error_count++;
695                                                         return;
696                                                 }
697                                                 int level;
698                                                 
699                                                 try {
700                                                         level = Int32.Parse (args [++i]);
701                                                 } catch {
702                                                         Report.Error (
703                                                                 1900,
704                                                                 "--wlevel requires an value from 0 to 4");
705                                                         return;
706                                                 }
707                                                 if (level < 0 || level > 4){
708                                                         Report.Error (1900, "Warning level must be 0 to 4");
709                                                         return;
710                                                 } else
711                                                         RootContext.WarningLevel = level;
712                                                 continue;
713                                                 
714                                         case "--about":
715                                                 About ();
716                                                 return;
717
718                                         case "--recurse":
719                                                 if ((i + 1) >= argc){
720                                                         Console.WriteLine ("--recurse requires an argument");
721                                                         error_count++;
722                                                         return;
723                                                 }
724                                                 errors += CompileFiles (args [++i], true);
725                                                 continue;
726                                                 
727                                         case "--timestamp":
728                                                 timestamps = true;
729                                                 last_time = DateTime.Now;
730                                                 continue;
731
732                                         case "--debug": case "-g":
733                                                 want_debugging_support = true;
734                                                 continue;
735
736                                         case "--noconfig":
737                                                 load_default_config = false;
738                                                 continue;
739
740                                         default:
741                                                 Console.WriteLine ("Unknown option: " + arg);
742                                                 errors++;
743                                                 continue;
744                                         }
745                                 }
746
747                                 CompileFiles (arg, false); 
748                         }
749
750                         if (tokenize)
751                                 return;
752                         
753                         if (first_source == null){
754                                 Report.Error (2008, "No files to compile were specified");
755                                 return;
756                         }
757
758                         if (Report.Errors > 0)
759                                 return;
760                         
761                         if (parse_only)
762                                 return;
763                         
764                         //
765                         // Load Core Library for default compilation
766                         //
767                         if (RootContext.StdLib)
768                                 references.Insert (0, "mscorlib");
769
770                         if (load_default_config)
771                                 DefineDefaultConfig ();
772
773                         if (errors > 0){
774                                 error ("Parsing failed");
775                                 return;
776                         }
777
778                         //
779                         // Load assemblies required
780                         //
781                         if (timestamps)
782                                 ShowTime ("Loading references");
783                         errors += LoadReferences ();
784                         if (timestamps)
785                                 ShowTime ("   References loaded");
786                         
787                         if (errors > 0){
788                                 error ("Could not load one or more assemblies");
789                                 return;
790                         }
791
792                         error_count = errors;
793
794                         //
795                         // Quick hack
796                         //
797                         if (output_file == null){
798                                 int pos = first_source.LastIndexOf (".");
799
800                                 if (pos > 0)
801                                         output_file = first_source.Substring (0, pos) + target_ext;
802                                 else
803                                         output_file = first_source + target_ext;
804                         }
805
806                         RootContext.CodeGen = new CodeGen (output_file, output_file,
807                                                            want_debugging_support);
808
809                         TypeManager.AddModule (RootContext.CodeGen.ModuleBuilder);
810
811                         //
812                         // Before emitting, we need to get the core
813                         // types emitted from the user defined types
814                         // or from the system ones.
815                         //
816                         if (timestamps)
817                                 ShowTime ("Initializing Core Types");
818                         if (!RootContext.StdLib){
819                                 RootContext.ResolveCore ();
820                                 if (Report.Errors > 0)
821                                         return;
822                         }
823                         
824                         TypeManager.InitCoreTypes ();
825                         if (timestamps)
826                                 ShowTime ("   Core Types done");
827
828                         //
829                         // The second pass of the compiler
830                         //
831                         if (timestamps)
832                                 ShowTime ("Resolving tree");
833                         RootContext.ResolveTree ();
834                         if (timestamps)
835                                 ShowTime ("Populate tree");
836                         RootContext.PopulateTypes ();
837                         
838                         if (RootContext.StdLib)
839                                 TypeManager.InitCodeHelpers ();
840                                 
841                         if (Report.Errors > 0){
842                                 error ("Compilation failed");
843                                 return;
844                         }
845                         
846                         //
847                         // The code generator
848                         //
849                         if (timestamps)
850                                 ShowTime ("Emitting code");
851                         RootContext.EmitCode ();
852                         if (timestamps)
853                                 ShowTime ("   done");
854
855                         if (Report.Errors > 0){
856                                 error ("Compilation failed");
857                                 return;
858                         }
859
860                         if (timestamps)
861                                 ShowTime ("Closing types");
862                         
863                         RootContext.CloseTypes ();
864
865                         PEFileKinds k = PEFileKinds.ConsoleApplication;
866                                 
867                         if (target == Target.Library || target == Target.Module)
868                                 k = PEFileKinds.Dll;
869                         else if (target == Target.Exe)
870                                 k = PEFileKinds.ConsoleApplication;
871                         else if (target == Target.WinExe)
872                                 k = PEFileKinds.WindowApplication;
873
874                         if (target == Target.Exe || target == Target.WinExe){
875                                 MethodInfo ep = RootContext.EntryPoint;
876
877                                 if (ep == null){
878                                         Report.Error (5001, "Program " + output_file +
879                                                               " does not have an entry point defined");
880                                         return;
881                                 }
882                                 
883                                 RootContext.CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
884                         }
885
886                         //
887                         // Add the resources
888                         //
889                         if (resources != null){
890                                 foreach (string file in resources)
891                                         RootContext.CodeGen.AssemblyBuilder.AddResourceFile (file, file);
892                         }
893                         
894                         RootContext.CodeGen.Save (output_file);
895                         if (timestamps)
896                                 ShowTime ("Saved output");
897
898                         if (Report.Errors > 0){
899                                 error ("Compilation failed");
900                                 return;
901                         } else if (Report.ProbeCode != 0){
902                                 error ("Failed to report code " + Report.ProbeCode);
903                                 Environment.Exit (124);
904                         }
905                 }
906
907         }
908 }