[System] Remove Process.Start and related API from TvOS/WatchOS.
[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 // 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 void Parse (SeekableStreamReader reader, SourceFile sourceFile, ModuleContainer module, ParserSession session, Report report)
165                 {
166                         var file = new CompilationSourceFile (module, sourceFile);
167                         module.AddTypeContainer (file);
168
169                         CSharpParser parser = new CSharpParser (reader, file, report, session);
170                         parser.parse ();
171                 }
172                 
173                 public static int Main (string[] args)
174                 {
175                         Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
176
177                         CommandLineParser cmd = new CommandLineParser (Console.Out);
178                         var settings = cmd.ParseArguments (args);
179                         if (settings == null)
180                                 return 1;
181
182                         if (cmd.HasBeenStopped)
183                                 return 0;
184
185                         Driver d = new Driver (new CompilerContext (settings, new ConsoleReportPrinter ()));
186
187                         if (d.Compile () && d.Report.Errors == 0) {
188                                 if (d.Report.Warnings > 0) {
189                                         Console.WriteLine ("Compilation succeeded - {0} warning(s)", d.Report.Warnings);
190                                 }
191                                 Environment.Exit (0);
192                                 return 0;
193                         }
194                         
195                         
196                         Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
197                                 d.Report.Errors, d.Report.Warnings);
198                         Environment.Exit (1);
199                         return 1;
200                 }
201
202                 public static string GetPackageFlags (string packages, Report report)
203                 {
204 #if MONO_FEATURE_PROCESS_START
205                         ProcessStartInfo pi = new ProcessStartInfo ();
206                         pi.FileName = "pkg-config";
207                         pi.RedirectStandardOutput = true;
208                         pi.UseShellExecute = false;
209                         pi.Arguments = "--libs " + packages;
210                         Process p = null;
211                         try {
212                                 p = Process.Start (pi);
213                         } catch (Exception e) {
214                                 if (report == null)
215                                         throw;
216
217                                 report.Error (-27, "Couldn't run pkg-config: " + e.Message);
218                                 return null;
219                         }
220                         
221                         if (p.StandardOutput == null) {
222                                 if (report == null)
223                                         throw new ApplicationException ("Specified package did not return any information");
224
225                                 report.Warning (-27, 1, "Specified package did not return any information");
226                                 p.Close ();
227                                 return null;
228                         }
229
230                         string pkgout = p.StandardOutput.ReadToEnd ();
231                         p.WaitForExit ();
232                         if (p.ExitCode != 0) {
233                                 if (report == null)
234                                         throw new ApplicationException (pkgout);
235
236                                 report.Error (-27, "Error running pkg-config. Check the above output.");
237                                 p.Close ();
238                                 return null;
239                         }
240
241                         p.Close ();
242                         return pkgout;
243 #else
244                         throw new NotSupportedException ("Process.Start is not supported on this platform.");
245 #endif // MONO_FEATURE_PROCESS_START
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                         if (settings.GetResourceStrings != null)
370                                 module.LoadGetResourceStrings (settings.GetResourceStrings);
371
372                         tr.Start (TimeReporter.TimerType.ModuleDefinitionTotal);
373                         module.Define ();
374                         tr.Stop (TimeReporter.TimerType.ModuleDefinitionTotal);
375
376                         if (Report.Errors > 0)
377                                 return false;
378
379                         if (settings.DocumentationFile != null) {
380                                 var doc = new DocumentationBuilder (module);
381                                 doc.OutputDocComment (output_file, settings.DocumentationFile);
382                         }
383
384                         assembly.Resolve ();
385                         
386                         if (Report.Errors > 0)
387                                 return false;
388
389
390                         tr.Start (TimeReporter.TimerType.EmitTotal);
391                         assembly.Emit ();
392                         tr.Stop (TimeReporter.TimerType.EmitTotal);
393
394                         if (Report.Errors > 0){
395                                 return false;
396                         }
397
398                         tr.Start (TimeReporter.TimerType.CloseTypes);
399                         module.CloseContainer ();
400                         tr.Stop (TimeReporter.TimerType.CloseTypes);
401
402                         tr.Start (TimeReporter.TimerType.Resouces);
403                         if (!settings.WriteMetadataOnly)
404                                 assembly.EmbedResources ();
405                         tr.Stop (TimeReporter.TimerType.Resouces);
406
407                         if (Report.Errors > 0)
408                                 return false;
409
410                         assembly.Save ();
411
412 #if STATIC
413                         references_loader.Dispose ();
414 #endif
415                         tr.StopTotal ();
416                         tr.ShowStats ();
417
418                         return Report.Errors == 0;
419                 }
420         }
421
422         //
423         // This is the only public entry point
424         //
425         public class CompilerCallableEntryPoint : MarshalByRefObject {
426                 public static bool InvokeCompiler (string [] args, TextWriter error)
427                 {
428                         try {
429                                 CommandLineParser cmd = new CommandLineParser (error);
430                                 var setting = cmd.ParseArguments (args);
431                                 if (setting == null)
432                                         return false;
433
434                                 var d = new Driver (new CompilerContext (setting, new StreamReportPrinter (error)));
435                                 return d.Compile ();
436                         } finally {
437                                 Reset ();
438                         }
439                 }
440
441                 public static int[] AllWarningNumbers {
442                         get {
443                                 return Report.AllWarnings;
444                         }
445                 }
446
447                 public static void Reset ()
448                 {
449                         Reset (true);
450                 }
451
452                 public static void PartialReset ()
453                 {
454                         Reset (false);
455                 }
456                 
457                 public static void Reset (bool full_flag)
458                 {
459                         Location.Reset ();
460                         
461                         if (!full_flag)
462                                 return;
463
464                         Linq.QueryBlock.TransparentParameter.Reset ();
465                         TypeInfo.Reset ();
466                 }
467         }
468 }