Wiring of BuildinType
[mono.git] / mcs / mcs / driver.cs
1 //
2 // driver.cs: The compiler command line driver.
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@gnu.org)
6 //   Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
12 //
13
14 using System;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Collections.Generic;
18 using System.IO;
19 using System.Text;
20 using System.Globalization;
21 using System.Diagnostics;
22
23 namespace Mono.CSharp
24 {
25         /// <summary>
26         ///    The compiler driver.
27         /// </summary>
28         class Driver
29         {
30                 readonly CompilerContext ctx;
31
32                 public Driver (CompilerContext ctx)
33                 {
34                         this.ctx = ctx;
35                 }
36
37                 Report Report {
38                         get {
39                                 return ctx.Report;
40                         }
41                 }
42
43                 void tokenize_file (CompilationUnit file)
44                 {
45                         Stream input;
46
47                         try {
48                                 input = File.OpenRead (file.Name);
49                         } catch {
50                                 Report.Error (2001, "Source file `" + file.Name + "' could not be found");
51                                 return;
52                         }
53
54                         using (input){
55                                 SeekableStreamReader reader = new SeekableStreamReader (input, ctx.Settings.Encoding);
56                                 Tokenizer lexer = new Tokenizer (reader, file, ctx);
57                                 int token, tokens = 0, errors = 0;
58
59                                 while ((token = lexer.token ()) != Token.EOF){
60                                         tokens++;
61                                         if (token == Token.ERROR)
62                                                 errors++;
63                                 }
64                                 Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
65                         }
66                         
67                         return;
68                 }
69
70                 void Parse (ModuleContainer module)
71                 {
72                         Location.Initialize ();
73
74                         bool tokenize_only = ctx.Settings.TokenizeOnly;
75                         var cu = Location.SourceFiles;
76                         for (int i = 0; i < cu.Count; ++i) {
77                                 if (tokenize_only) {
78                                         tokenize_file (cu[i]);
79                                 } else {
80                                         Parse (cu[i], module);
81                                 }
82                         }
83                 }
84
85                 void Parse (CompilationUnit file, ModuleContainer module)
86                 {
87                         Stream input;
88
89                         try {
90                                 input = File.OpenRead (file.Name);
91                         } catch {
92                                 Report.Error (2001, "Source file `{0}' could not be found", file.Name);
93                                 return;
94                         }
95
96                         // Check 'MZ' header
97                         if (input.ReadByte () == 77 && input.ReadByte () == 90) {
98                                 Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
99                                 input.Close ();
100                                 return;
101                         }
102
103                         input.Position = 0;
104                         SeekableStreamReader reader = new SeekableStreamReader (input, ctx.Settings.Encoding);
105
106                         Parse (reader, file, module);
107                         reader.Dispose ();
108                         input.Close ();
109                 }       
110                 
111                 public void Parse (SeekableStreamReader reader, CompilationUnit file, ModuleContainer module)
112                 {
113                         CSharpParser parser = new CSharpParser (reader, file, module);
114                         parser.parse ();
115                 }
116                 
117                 public static int Main (string[] args)
118                 {
119                         Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
120
121                         var r = new Report (new ConsoleReportPrinter ());
122                         CommandLineParser cmd = new CommandLineParser (r);
123                         var settings = cmd.ParseArguments (args);
124                         if (settings == null || r.Errors > 0)
125                                 return 1;
126
127                         if (cmd.HasBeenStopped)
128                                 return 0;
129
130                         Driver d = new Driver (new CompilerContext (settings, r));
131
132                         if (d.Compile () && d.Report.Errors == 0) {
133                                 if (d.Report.Warnings > 0) {
134                                         Console.WriteLine ("Compilation succeeded - {0} warning(s)", d.Report.Warnings);
135                                 }
136                                 Environment.Exit (0);
137                                 return 0;
138                         }
139                         
140                         
141                         Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
142                                 d.Report.Errors, d.Report.Warnings);
143                         Environment.Exit (1);
144                         return 1;
145                 }
146
147                 public static string GetPackageFlags (string packages, Report report)
148                 {
149                         ProcessStartInfo pi = new ProcessStartInfo ();
150                         pi.FileName = "pkg-config";
151                         pi.RedirectStandardOutput = true;
152                         pi.UseShellExecute = false;
153                         pi.Arguments = "--libs " + packages;
154                         Process p = null;
155                         try {
156                                 p = Process.Start (pi);
157                         } catch (Exception e) {
158                                 if (report == null)
159                                         throw;
160
161                                 report.Error (-27, "Couldn't run pkg-config: " + e.Message);
162                                 return null;
163                         }
164                         
165                         if (p.StandardOutput == null) {
166                                 if (report == null)
167                                         throw new ApplicationException ("Specified package did not return any information");
168
169                                 report.Warning (-27, 1, "Specified package did not return any information");
170                                 p.Close ();
171                                 return null;
172                         }
173
174                         string pkgout = p.StandardOutput.ReadToEnd ();
175                         p.WaitForExit ();
176                         if (p.ExitCode != 0) {
177                                 if (report == null)
178                                         throw new ApplicationException (pkgout);
179
180                                 report.Error (-27, "Error running pkg-config. Check the above output.");
181                                 p.Close ();
182                                 return null;
183                         }
184
185                         p.Close ();
186                         return pkgout;
187                 }
188
189                 //
190                 // Main compilation method
191                 //
192                 public bool Compile ()
193                 {
194                         var settings = ctx.Settings;
195
196                         //
197                         // If we are an exe, require a source file for the entry point or
198                         // if there is nothing to put in the assembly, and we are not a library
199                         //
200                         if (Location.FirstFile == null &&
201                                 ((settings.Target == Target.Exe || settings.Target == Target.WinExe || settings.Target == Target.Module) ||
202                                 settings.Resources == null)) {
203                                 Report.Error (2008, "No files to compile were specified");
204                                 return false;
205                         }
206
207                         TimeReporter tr = new TimeReporter (settings.Timestamps);
208                         ctx.TimeReporter = tr;
209                         tr.StartTotal ();
210
211                         var module = new ModuleContainer (ctx);
212                         RootContext.ToplevelTypes = module;
213
214                         tr.Start (TimeReporter.TimerType.ParseTotal);
215                         Parse (module);
216                         tr.Stop (TimeReporter.TimerType.ParseTotal);
217
218                         if (Report.Errors > 0)
219                                 return false;
220
221                         if (settings.TokenizeOnly || settings.ParseOnly)
222                                 return true;
223
224                         if (RootContext.ToplevelTypes.NamespaceEntry != null)
225                                 throw new InternalErrorException ("who set it?");
226
227                         var output_file = settings.OutputFile;
228                         string output_file_name;
229                         if (output_file == null) {
230                                 output_file_name = Location.FirstFile;
231
232                                 if (output_file_name == null) {
233                                         Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
234                                         return false;
235                                 }
236
237                                 int pos = output_file_name.LastIndexOf ('.');
238
239                                 if (pos > 0)
240                                         output_file_name = output_file_name.Substring (0, pos);
241                                 
242                                 output_file_name += settings.TargetExt;
243                                 output_file = output_file_name;
244                         } else {
245                                 output_file_name = Path.GetFileName (output_file);
246                         }
247
248 #if STATIC
249                         var importer = new StaticImporter (module);
250                         var references_loader = new StaticLoader (importer, ctx);
251
252                         tr.Start (TimeReporter.TimerType.AssemblyBuilderSetup);
253                         var assembly = new AssemblyDefinitionStatic (module, references_loader, output_file_name, output_file);
254                         assembly.Create (references_loader.Domain);
255                         tr.Stop (TimeReporter.TimerType.AssemblyBuilderSetup);
256
257                         // Create compiler types first even before any referenced
258                         // assembly is loaded to allow forward referenced types from
259                         // loaded assembly into compiled builder to be resolved
260                         // correctly
261                         tr.Start (TimeReporter.TimerType.CreateTypeTotal);
262                         module.CreateType ();
263                         importer.AddCompiledAssembly (assembly);
264                         tr.Stop (TimeReporter.TimerType.CreateTypeTotal);
265
266                         references_loader.LoadReferences (module);
267
268                         tr.Start (TimeReporter.TimerType.PredefinedTypesInit);
269                         if (!ctx.BuildinTypes.CheckDefinitions (module))
270                                 return false;
271
272                         tr.Stop (TimeReporter.TimerType.PredefinedTypesInit);
273
274                         references_loader.LoadModules (assembly, module.GlobalRootNamespace);
275 #else
276                         var assembly = new AssemblyDefinitionDynamic (module, output_file_name, output_file);
277                         module.SetDeclaringAssembly (assembly);
278
279                         var importer = new ReflectionImporter (module, ctx.BuildinTypes);
280                         assembly.Importer = importer;
281
282                         var loader = new DynamicLoader (importer, ctx);
283                         loader.LoadReferences (module);
284
285                         if (!ctx.BuildinTypes.CheckDefinitions (module))
286                                 return false;
287
288                         if (!assembly.Create (AppDomain.CurrentDomain, AssemblyBuilderAccess.Save))
289                                 return false;
290
291                         module.CreateType ();
292
293                         loader.LoadModules (assembly, module.GlobalRootNamespace);
294 #endif
295                         tr.Start (TimeReporter.TimerType.ModuleDefinitionTotal);
296                         module.Define ();
297                         tr.Stop (TimeReporter.TimerType.ModuleDefinitionTotal);
298
299                         if (Report.Errors > 0)
300                                 return false;
301
302                         if (settings.Documentation != null &&
303                                 !settings.Documentation.OutputDocComment (
304                                         output_file, Report))
305                                 return false;
306
307                         //
308                         // Verify using aliases now
309                         //
310                         tr.Start (TimeReporter.TimerType.UsingVerification);
311                         NamespaceEntry.VerifyAllUsing ();
312                         tr.Stop (TimeReporter.TimerType.UsingVerification);
313                         
314                         if (Report.Errors > 0){
315                                 return false;
316                         }
317
318                         assembly.Resolve ();
319                         
320                         if (Report.Errors > 0)
321                                 return false;
322
323
324                         tr.Start (TimeReporter.TimerType.EmitTotal);
325                         assembly.Emit ();
326                         tr.Stop (TimeReporter.TimerType.EmitTotal);
327
328                         if (Report.Errors > 0){
329                                 return false;
330                         }
331
332                         tr.Start (TimeReporter.TimerType.CloseTypes);
333                         module.CloseType ();
334                         tr.Stop (TimeReporter.TimerType.CloseTypes);
335
336                         tr.Start (TimeReporter.TimerType.Resouces);
337                         assembly.EmbedResources ();
338                         tr.Stop (TimeReporter.TimerType.Resouces);
339
340                         if (Report.Errors > 0)
341                                 return false;
342
343                         assembly.Save ();
344
345 #if STATIC
346                         references_loader.Dispose ();
347 #endif
348                         tr.StopTotal ();
349                         tr.ShowStats ();
350
351                         return Report.Errors == 0;
352                 }
353         }
354
355         //
356         // This is the only public entry point
357         //
358         public class CompilerCallableEntryPoint : MarshalByRefObject {
359                 public static bool InvokeCompiler (string [] args, TextWriter error)
360                 {
361                         try {
362                                 var r = new Report (new StreamReportPrinter (error));
363                                 CommandLineParser cmd = new CommandLineParser (r, error);
364                                 var setting = cmd.ParseArguments (args);
365                                 if (setting == null || r.Errors > 0)
366                                         return false;
367
368                                 var d = new Driver (new CompilerContext (setting, r));
369                                 return d.Compile ();
370                         } finally {
371                                 Reset ();
372                         }
373                 }
374
375                 public static int[] AllWarningNumbers {
376                         get {
377                                 return Report.AllWarnings;
378                         }
379                 }
380
381                 public static void Reset ()
382                 {
383                         Reset (true);
384                 }
385
386                 public static void PartialReset ()
387                 {
388                         Reset (false);
389                 }
390                 
391                 public static void Reset (bool full_flag)
392                 {
393                         CSharpParser.yacc_verbose_flag = 0;
394                         Location.Reset ();
395                         
396                         if (!full_flag)
397                                 return;
398
399                         RootContext.Reset (full_flag);
400                         TypeManager.Reset ();
401                         ReferenceContainer.Reset ();
402                         PointerContainer.Reset ();
403                         Parameter.Reset ();
404
405                         CastFromDecimal.Reset ();
406                         StringConcat.Reset ();
407                         
408                         NamespaceEntry.Reset ();
409                         Attribute.Reset ();
410                         AnonymousTypeClass.Reset ();
411                         AnonymousMethodBody.Reset ();
412                         AnonymousMethodStorey.Reset ();
413                         SymbolWriter.Reset ();
414                         Switch.Reset ();
415                         Linq.QueryBlock.TransparentParameter.Reset ();
416                         Convert.Reset ();
417                         TypeInfo.Reset ();
418                 }
419         }
420 }