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 | // Copyright 2011 Xamarin Inc |
---|
13 | // |
---|
14 | |
---|
15 | using System; |
---|
16 | using System.Reflection; |
---|
17 | using System.Reflection.Emit; |
---|
18 | using System.Collections.Generic; |
---|
19 | using System.IO; |
---|
20 | using System.Text; |
---|
21 | using System.Globalization; |
---|
22 | using System.Diagnostics; |
---|
23 | using System.Threading; |
---|
24 | |
---|
25 | namespace Mono.CSharp |
---|
26 | { |
---|
27 | /// <summary> |
---|
28 | /// The compiler driver. |
---|
29 | /// </summary> |
---|
30 | class Driver |
---|
31 | { |
---|
32 | readonly CompilerContext ctx; |
---|
33 | |
---|
34 | public Driver (CompilerContext ctx) |
---|
35 | { |
---|
36 | this.ctx = ctx; |
---|
37 | } |
---|
38 | |
---|
39 | Report Report { |
---|
40 | get { |
---|
41 | return ctx.Report; |
---|
42 | } |
---|
43 | } |
---|
44 | |
---|
45 | void tokenize_file (SourceFile sourceFile, ModuleContainer module, ParserSession session) |
---|
46 | { |
---|
47 | Stream input; |
---|
48 | |
---|
49 | try { |
---|
50 | input = File.OpenRead (sourceFile.Name); |
---|
51 | } catch { |
---|
52 | Report.Error (2001, "Source file `" + sourceFile.Name + "' could not be found"); |
---|
53 | return; |
---|
54 | } |
---|
55 | |
---|
56 | using (input){ |
---|
57 | SeekableStreamReader reader = new SeekableStreamReader (input, ctx.Settings.Encoding); |
---|
58 | var file = new CompilationSourceFile (module, sourceFile); |
---|
59 | |
---|
60 | Tokenizer lexer = new Tokenizer (reader, file, session, ctx.Report); |
---|
61 | int token, tokens = 0, errors = 0; |
---|
62 | |
---|
63 | while ((token = lexer.token ()) != Token.EOF){ |
---|
64 | tokens++; |
---|
65 | if (token == Token.ERROR) |
---|
66 | errors++; |
---|
67 | } |
---|
68 | Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors"); |
---|
69 | } |
---|
70 | |
---|
71 | return; |
---|
72 | } |
---|
73 | |
---|
74 | void Parse (ModuleContainer module) |
---|
75 | { |
---|
76 | bool tokenize_only = module.Compiler.Settings.TokenizeOnly; |
---|
77 | var sources = module.Compiler.SourceFiles; |
---|
78 | |
---|
79 | Location.Initialize (sources); |
---|
80 | |
---|
81 | var session = new ParserSession { |
---|
82 | UseJayGlobalArrays = true, |
---|
83 | LocatedTokens = new LocatedToken[15000] |
---|
84 | }; |
---|
85 | |
---|
86 | for (int i = 0; i < sources.Count; ++i) { |
---|
87 | if (tokenize_only) { |
---|
88 | tokenize_file (sources[i], module, session); |
---|
89 | } else { |
---|
90 | Parse (sources[i], module, session, Report); |
---|
91 | } |
---|
92 | } |
---|
93 | } |
---|
94 | |
---|
95 | #if false |
---|
96 | void ParseParallel (ModuleContainer module) |
---|
97 | { |
---|
98 | var sources = module.Compiler.SourceFiles; |
---|
99 | |
---|
100 | Location.Initialize (sources); |
---|
101 | |
---|
102 | var pcount = Environment.ProcessorCount; |
---|
103 | var threads = new Thread[System.Math.Max (2, pcount - 1)]; |
---|
104 | |
---|
105 | for (int i = 0; i < threads.Length; ++i) { |
---|
106 | var t = new Thread (l => { |
---|
107 | var session = new ParserSession () { |
---|
108 | //UseJayGlobalArrays = true, |
---|
109 | }; |
---|
110 | |
---|
111 | var report = new Report (ctx, Report.Printer); // TODO: Implement flush at once printer |
---|
112 | |
---|
113 | for (int ii = (int) l; ii < sources.Count; ii += threads.Length) { |
---|
114 | Parse (sources[ii], module, session, report); |
---|
115 | } |
---|
116 | |
---|
117 | // TODO: Merge warning regions |
---|
118 | }); |
---|
119 | |
---|
120 | t.Start (i); |
---|
121 | threads[i] = t; |
---|
122 | } |
---|
123 | |
---|
124 | for (int t = 0; t < threads.Length; ++t) { |
---|
125 | threads[t].Join (); |
---|
126 | } |
---|
127 | } |
---|
128 | #endif |
---|
129 | |
---|
130 | public void Parse (SourceFile file, ModuleContainer module, ParserSession session, Report report) |
---|
131 | { |
---|
132 | Stream input; |
---|
133 | |
---|
134 | try { |
---|
135 | input = File.OpenRead (file.Name); |
---|
136 | } catch { |
---|
137 | report.Error (2001, "Source file `{0}' could not be found", file.Name); |
---|
138 | return; |
---|
139 | } |
---|
140 | |
---|
141 | // Check 'MZ' header |
---|
142 | if (input.ReadByte () == 77 && input.ReadByte () == 90) { |
---|
143 | |
---|
144 | report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name); |
---|
145 | input.Close (); |
---|
146 | return; |
---|
147 | } |
---|
148 | |
---|
149 | input.Position = 0; |
---|
150 | SeekableStreamReader reader = new SeekableStreamReader (input, ctx.Settings.Encoding, session.StreamReaderBuffer); |
---|
151 | |
---|
152 | Parse (reader, file, module, session, report); |
---|
153 | |
---|
154 | if (ctx.Settings.GenerateDebugInfo && report.Errors == 0 && !file.HasChecksum) { |
---|
155 | input.Position = 0; |
---|
156 | var checksum = session.GetChecksumAlgorithm (); |
---|
157 | file.SetChecksum (checksum.ComputeHash (input)); |
---|
158 | } |
---|
159 | |
---|
160 | reader.Dispose (); |
---|
161 | input.Close (); |
---|
162 | } |
---|
163 | |
---|
164 | public static CSharpParser Parse (SeekableStreamReader reader, SourceFile sourceFile, ModuleContainer module, ParserSession session, Report report, int lineModifier = 0, int colModifier = 0) |
---|
165 | { |
---|
166 | var file = new CompilationSourceFile (module, sourceFile); |
---|
167 | module.AddTypeContainer(file); |
---|
168 | |
---|
169 | CSharpParser parser = new CSharpParser (reader, file, report, session); |
---|
170 | parser.Lexer.Line += lineModifier; |
---|
171 | parser.Lexer.Column += colModifier; |
---|
172 | parser.Lexer.sbag = new SpecialsBag (); |
---|
173 | parser.parse (); |
---|
174 | return parser; |
---|
175 | } |
---|
176 | |
---|
177 | public static int Main (string[] args) |
---|
178 | { |
---|
179 | Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t"; |
---|
180 | |
---|
181 | CommandLineParser cmd = new CommandLineParser (Console.Out); |
---|
182 | var settings = cmd.ParseArguments (args); |
---|
183 | if (settings == null) |
---|
184 | return 1; |
---|
185 | |
---|
186 | if (cmd.HasBeenStopped) |
---|
187 | return 0; |
---|
188 | |
---|
189 | Driver d = new Driver (new CompilerContext (settings, new ConsoleReportPrinter ())); |
---|
190 | |
---|
191 | if (d.Compile () && d.Report.Errors == 0) { |
---|
192 | if (d.Report.Warnings > 0) { |
---|
193 | Console.WriteLine ("Compilation succeeded - {0} warning(s)", d.Report.Warnings); |
---|
194 | } |
---|
195 | Environment.Exit (0); |
---|
196 | return 0; |
---|
197 | } |
---|
198 | |
---|
199 | |
---|
200 | Console.WriteLine("Compilation failed: {0} error(s), {1} warnings", |
---|
201 | d.Report.Errors, d.Report.Warnings); |
---|
202 | Environment.Exit (1); |
---|
203 | return 1; |
---|
204 | } |
---|
205 | |
---|
206 | public static string GetPackageFlags (string packages, Report report) |
---|
207 | { |
---|
208 | ProcessStartInfo pi = new ProcessStartInfo (); |
---|
209 | pi.FileName = "pkg-config"; |
---|
210 | pi.RedirectStandardOutput = true; |
---|
211 | pi.UseShellExecute = false; |
---|
212 | pi.Arguments = "--libs " + packages; |
---|
213 | Process p = null; |
---|
214 | try { |
---|
215 | p = Process.Start (pi); |
---|
216 | } catch (Exception e) { |
---|
217 | if (report == null) |
---|
218 | throw; |
---|
219 | |
---|
220 | report.Error (-27, "Couldn't run pkg-config: " + e.Message); |
---|
221 | return null; |
---|
222 | } |
---|
223 | |
---|
224 | if (p.StandardOutput == null) { |
---|
225 | if (report == null) |
---|
226 | throw new ApplicationException ("Specified package did not return any information"); |
---|
227 | |
---|
228 | report.Warning (-27, 1, "Specified package did not return any information"); |
---|
229 | p.Close (); |
---|
230 | return null; |
---|
231 | } |
---|
232 | |
---|
233 | string pkgout = p.StandardOutput.ReadToEnd (); |
---|
234 | p.WaitForExit (); |
---|
235 | if (p.ExitCode != 0) { |
---|
236 | if (report == null) |
---|
237 | throw new ApplicationException (pkgout); |
---|
238 | |
---|
239 | report.Error (-27, "Error running pkg-config. Check the above output."); |
---|
240 | p.Close (); |
---|
241 | return null; |
---|
242 | } |
---|
243 | |
---|
244 | p.Close (); |
---|
245 | return pkgout; |
---|
246 | } |
---|
247 | |
---|
248 | // |
---|
249 | // Main compilation method |
---|
250 | // |
---|
251 | public bool Compile () |
---|
252 | { |
---|
253 | var settings = ctx.Settings; |
---|
254 | |
---|
255 | // |
---|
256 | // If we are an exe, require a source file for the entry point or |
---|
257 | // if there is nothing to put in the assembly, and we are not a library |
---|
258 | // |
---|
259 | if (settings.FirstSourceFile == null && |
---|
260 | ((settings.Target == Target.Exe || settings.Target == Target.WinExe || settings.Target == Target.Module) || |
---|
261 | settings.Resources == null)) { |
---|
262 | Report.Error (2008, "No files to compile were specified"); |
---|
263 | return false; |
---|
264 | } |
---|
265 | |
---|
266 | if (settings.Platform == Platform.AnyCPU32Preferred && (settings.Target == Target.Library || settings.Target == Target.Module)) { |
---|
267 | Report.Error (4023, "Platform option `anycpu32bitpreferred' is valid only for executables"); |
---|
268 | return false; |
---|
269 | } |
---|
270 | |
---|
271 | TimeReporter tr = new TimeReporter (settings.Timestamps); |
---|
272 | ctx.TimeReporter = tr; |
---|
273 | tr.StartTotal (); |
---|
274 | |
---|
275 | var module = new ModuleContainer (ctx); |
---|
276 | RootContext.ToplevelTypes = module; |
---|
277 | |
---|
278 | tr.Start (TimeReporter.TimerType.ParseTotal); |
---|
279 | Parse (module); |
---|
280 | tr.Stop (TimeReporter.TimerType.ParseTotal); |
---|
281 | |
---|
282 | if (Report.Errors > 0) |
---|
283 | return false; |
---|
284 | |
---|
285 | if (settings.TokenizeOnly || settings.ParseOnly) { |
---|
286 | tr.StopTotal (); |
---|
287 | tr.ShowStats (); |
---|
288 | return true; |
---|
289 | } |
---|
290 | |
---|
291 | var output_file = settings.OutputFile; |
---|
292 | string output_file_name; |
---|
293 | if (output_file == null) { |
---|
294 | var source_file = settings.FirstSourceFile; |
---|
295 | |
---|
296 | if (source_file == null) { |
---|
297 | Report.Error (1562, "If no source files are specified you must specify the output file with -out:"); |
---|
298 | return false; |
---|
299 | } |
---|
300 | |
---|
301 | output_file_name = source_file.Name; |
---|
302 | int pos = output_file_name.LastIndexOf ('.'); |
---|
303 | |
---|
304 | if (pos > 0) |
---|
305 | output_file_name = output_file_name.Substring (0, pos); |
---|
306 | |
---|
307 | output_file_name += settings.TargetExt; |
---|
308 | output_file = output_file_name; |
---|
309 | } else { |
---|
310 | output_file_name = Path.GetFileName (output_file); |
---|
311 | |
---|
312 | if (string.IsNullOrEmpty (Path.GetFileNameWithoutExtension (output_file_name)) || |
---|
313 | output_file_name.IndexOfAny (Path.GetInvalidFileNameChars ()) >= 0) { |
---|
314 | Report.Error (2021, "Output file name is not valid"); |
---|
315 | return false; |
---|
316 | } |
---|
317 | } |
---|
318 | |
---|
319 | #if STATIC |
---|
320 | var importer = new StaticImporter (module); |
---|
321 | var references_loader = new StaticLoader (importer, ctx); |
---|
322 | |
---|
323 | tr.Start (TimeReporter.TimerType.AssemblyBuilderSetup); |
---|
324 | var assembly = new AssemblyDefinitionStatic (module, references_loader, output_file_name, output_file); |
---|
325 | assembly.Create (references_loader.Domain); |
---|
326 | tr.Stop (TimeReporter.TimerType.AssemblyBuilderSetup); |
---|
327 | |
---|
328 | // Create compiler types first even before any referenced |
---|
329 | // assembly is loaded to allow forward referenced types from |
---|
330 | // loaded assembly into compiled builder to be resolved |
---|
331 | // correctly |
---|
332 | tr.Start (TimeReporter.TimerType.CreateTypeTotal); |
---|
333 | module.CreateContainer (); |
---|
334 | importer.AddCompiledAssembly (assembly); |
---|
335 | references_loader.CompiledAssembly = assembly; |
---|
336 | tr.Stop (TimeReporter.TimerType.CreateTypeTotal); |
---|
337 | |
---|
338 | references_loader.LoadReferences (module); |
---|
339 | |
---|
340 | tr.Start (TimeReporter.TimerType.PredefinedTypesInit); |
---|
341 | if (!ctx.BuiltinTypes.CheckDefinitions (module)) |
---|
342 | return false; |
---|
343 | |
---|
344 | tr.Stop (TimeReporter.TimerType.PredefinedTypesInit); |
---|
345 | |
---|
346 | references_loader.LoadModules (assembly, module.GlobalRootNamespace); |
---|
347 | #else |
---|
348 | var assembly = new AssemblyDefinitionDynamic (module, output_file_name, output_file); |
---|
349 | module.SetDeclaringAssembly (assembly); |
---|
350 | |
---|
351 | var importer = new ReflectionImporter (module, ctx.BuiltinTypes); |
---|
352 | assembly.Importer = importer; |
---|
353 | |
---|
354 | var loader = new DynamicLoader (importer, ctx); |
---|
355 | loader.LoadReferences (module); |
---|
356 | |
---|
357 | if (!ctx.BuiltinTypes.CheckDefinitions (module)) |
---|
358 | return false; |
---|
359 | |
---|
360 | if (!assembly.Create (AppDomain.CurrentDomain, AssemblyBuilderAccess.Save)) |
---|
361 | return false; |
---|
362 | |
---|
363 | module.CreateContainer (); |
---|
364 | |
---|
365 | loader.LoadModules (assembly, module.GlobalRootNamespace); |
---|
366 | #endif |
---|
367 | module.InitializePredefinedTypes (); |
---|
368 | |
---|
369 | tr.Start (TimeReporter.TimerType.ModuleDefinitionTotal); |
---|
370 | module.Define (); |
---|
371 | tr.Stop (TimeReporter.TimerType.ModuleDefinitionTotal); |
---|
372 | |
---|
373 | if (Report.Errors > 0) |
---|
374 | return false; |
---|
375 | |
---|
376 | if (settings.DocumentationFile != null) { |
---|
377 | var doc = new DocumentationBuilder (module); |
---|
378 | doc.OutputDocComment (output_file, settings.DocumentationFile); |
---|
379 | } |
---|
380 | |
---|
381 | assembly.Resolve (); |
---|
382 | |
---|
383 | if (Report.Errors > 0) |
---|
384 | return false; |
---|
385 | |
---|
386 | |
---|
387 | tr.Start (TimeReporter.TimerType.EmitTotal); |
---|
388 | assembly.Emit (); |
---|
389 | tr.Stop (TimeReporter.TimerType.EmitTotal); |
---|
390 | |
---|
391 | if (Report.Errors > 0){ |
---|
392 | return false; |
---|
393 | } |
---|
394 | |
---|
395 | tr.Start (TimeReporter.TimerType.CloseTypes); |
---|
396 | module.CloseContainer (); |
---|
397 | tr.Stop (TimeReporter.TimerType.CloseTypes); |
---|
398 | |
---|
399 | tr.Start (TimeReporter.TimerType.Resouces); |
---|
400 | if (!settings.WriteMetadataOnly) |
---|
401 | assembly.EmbedResources (); |
---|
402 | tr.Stop (TimeReporter.TimerType.Resouces); |
---|
403 | |
---|
404 | if (Report.Errors > 0) |
---|
405 | return false; |
---|
406 | |
---|
407 | assembly.Save (); |
---|
408 | |
---|
409 | #if STATIC |
---|
410 | references_loader.Dispose (); |
---|
411 | #endif |
---|
412 | tr.StopTotal (); |
---|
413 | tr.ShowStats (); |
---|
414 | |
---|
415 | return Report.Errors == 0; |
---|
416 | } |
---|
417 | } |
---|
418 | |
---|
419 | public class CompilerCompilationUnit { |
---|
420 | public ModuleContainer ModuleCompiled { get; set; } |
---|
421 | public LocationsBag LocationsBag { get; set; } |
---|
422 | public SpecialsBag SpecialsBag { get; set; } |
---|
423 | public IDictionary<string, bool> Conditionals { get; set; } |
---|
424 | public object LastYYValue { get; set; } |
---|
425 | } |
---|
426 | |
---|
427 | // |
---|
428 | // This is the only public entry point |
---|
429 | // |
---|
430 | public class CompilerCallableEntryPoint : MarshalByRefObject |
---|
431 | { |
---|
432 | public static bool InvokeCompiler (string [] args, TextWriter error) |
---|
433 | { |
---|
434 | try { |
---|
435 | CommandLineParser cmd = new CommandLineParser (error); |
---|
436 | var setting = cmd.ParseArguments (args); |
---|
437 | if (setting == null) |
---|
438 | return false; |
---|
439 | |
---|
440 | var d = new Driver (new CompilerContext (setting, new StreamReportPrinter (error))); |
---|
441 | return d.Compile (); |
---|
442 | } finally { |
---|
443 | Reset (); |
---|
444 | } |
---|
445 | } |
---|
446 | |
---|
447 | public static int[] AllWarningNumbers { |
---|
448 | get { |
---|
449 | return Report.AllWarnings; |
---|
450 | } |
---|
451 | } |
---|
452 | |
---|
453 | public static void Reset () |
---|
454 | { |
---|
455 | Reset (true); |
---|
456 | } |
---|
457 | |
---|
458 | public static void PartialReset () |
---|
459 | { |
---|
460 | Reset (false); |
---|
461 | } |
---|
462 | |
---|
463 | public static void Reset (bool full_flag) |
---|
464 | { |
---|
465 | Location.Reset (); |
---|
466 | |
---|
467 | if (!full_flag) |
---|
468 | return; |
---|
469 | |
---|
470 | Linq.QueryBlock.TransparentParameter.Reset (); |
---|
471 | TypeInfo.Reset (); |
---|
472 | } |
---|
473 | } |
---|
474 | |
---|
475 | } |
---|